#include <stdint.h>
#include <utility>
#include <vector>
#include "base/command_line.h"
#include "base/files/scoped_temp_dir.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/ranges/algorithm.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/process_lock.h"
#include "content/browser/renderer_host/frame_navigation_entry.h"
#include "content/browser/renderer_host/frame_tree.h"
#include "content/browser/renderer_host/navigation_controller_impl.h"
#include "content/browser/renderer_host/navigation_type.h"
#include "content/browser/renderer_host/navigation_entry_impl.h"
#include "content/browser/renderer_host/navigation_entry_restore_context_impl.h"
#include "content/browser/renderer_host/navigation_request.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/renderer_host/renderer_cancellation_throttle.h"
#include "content/browser/site_info.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/browser/web_contents/web_contents_view.h"
#include "content/common/content_navigation_policy.h"
#include "content/common/features.h"
#include "content/common/frame_messages.mojom.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/site_isolation_policy.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/bindings_policy.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_features.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/back_forward_cache_util.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_content_browser_client.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/download_test_observer.h"
#include "content/public/test/navigation_handle_observer.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h"
#include "content/public/test/url_loader_interceptor.h"
#include "content/shell/browser/shell.h"
#include "content/shell/browser/shell_download_manager_delegate.h"
#include "content/shell/common/shell_switches.h"
#include "content/test/content_browser_test_utils_internal.h"
#include "content/test/did_commit_navigation_interceptor.h"
#include "content/test/render_document_feature.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/controllable_http_response.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/url_request/url_request_failed_job.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/blink/public/common/loader/referrer_utils.h"
#include "third_party/blink/public/common/page_state/page_state_serialization.h"
#include "third_party/blink/public/common/renderer_preferences/renderer_preferences.h"
#include "third_party/blink/public/mojom/frame/frame.mojom-test-utils.h"
#include "third_party/blink/public/mojom/frame/user_activation_update_types.mojom.h"
#include "ui/display/display_util.h"
#include "url/url_constants.h"
namespace content {
namespace {
using testing::ElementsAre;
using testing::IsEmpty;
using InitialNavigationEntryState =
NavigationEntryImpl::InitialNavigationEntryState;
const char kAddNamedFrameScript[] =
"var f = document.createElement('iframe');"
"f.name = 'foo-frame-name';"
"document.body.appendChild(f);";
const char kRemoveFrameScript[] =
"var f = document.querySelector('iframe');"
"f.parentNode.removeChild(f);";
const char kAddEmptyFrameScript[] =
"let iframe = document.createElement('iframe');"
"document.body.appendChild(iframe);";
const char kAddFrameWithSrcScript[] =
"let iframe = document.createElement('iframe');"
"iframe.src = $1;"
"document.body.appendChild(iframe);";
}
class NavigationControllerBrowserTestBase : public ContentBrowserTest {
public:
NavigationControllerBrowserTestBase() {
feature_list_.InitWithFeaturesAndParameters(
{{kQueueNavigationsWhileWaitingForCommit, {{"level", "full"}}}}, {});
}
protected:
void SetUpOnMainThread() override {
host_resolver()->AddRule("*", "127.0.0.1");
content::SetupCrossSiteRedirector(embedded_test_server());
ASSERT_TRUE(embedded_test_server()->Start());
}
void SetUpCommandLine(base::CommandLine* command_line) override {
ContentBrowserTest::SetUpCommandLine(command_line);
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kExposeInternalsForTesting);
}
WebContentsImpl* contents() const {
return static_cast<WebContentsImpl*>(shell()->web_contents());
}
void LoadDataWithBaseURL(const GURL& base_url,
const std::string& data,
const GURL& history_url,
const std::string& title,
bool use_load_data_as_string_with_base_url) {
TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
TitleWatcher title_watcher(shell()->web_contents(),
base::UTF8ToUTF16(title));
if (use_load_data_as_string_with_base_url) {
#if BUILDFLAG(IS_ANDROID)
shell()->LoadDataAsStringWithBaseURL(history_url, data, base_url);
#else
NOTREACHED();
#endif
} else {
shell()->LoadDataWithBaseURL(history_url, data, base_url);
}
same_tab_observer.Wait();
std::u16string actual_title = title_watcher.WaitAndGetTitle();
EXPECT_EQ(title, base::UTF16ToUTF8(actual_title));
}
private:
base::test::ScopedFeatureList feature_list_;
};
class NavigationControllerBrowserTest
: public NavigationControllerBrowserTestBase,
public ::testing::WithParamInterface<
std::tuple<std::string /* render_document_level */,
bool /* enable_back_forward_cache*/>> {
public:
NavigationControllerBrowserTest() {
InitAndEnableRenderDocumentFeature(&feature_list_for_render_document_,
std::get<0>(GetParam()));
InitBackForwardCacheFeature(&feature_list_for_back_forward_cache_,
std::get<1>(GetParam()));
}
static std::string DescribeParams(
const testing::TestParamInfo<ParamType>& info) {
auto [render_document_level, enable_back_forward_cache] = info.param;
return base::StringPrintf(
"%s_%s",
GetRenderDocumentLevelNameForTestParams(render_document_level).c_str(),
enable_back_forward_cache ? "BFCacheEnabled" : "BFCacheDisabled");
}
RenderFrameHostImpl* current_main_frame_host() {
return static_cast<RenderFrameHostImpl*>(contents()->GetPrimaryMainFrame());
}
protected:
bool IsFractionalScrollOffsetsEnabled() {
std::string script =
"internals.runtimeFlags.fractionalScrollOffsetsEnabled";
return EvalJs(shell(), script).ExtractBool();
}
int64_t CreateAndSubmitForm(const GURL& form_submit_url) {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
TestNavigationObserver form_nav_observer(contents());
EXPECT_TRUE(ExecJs(contents(),
JsReplace(R"(var form = document.createElement('form');
form.method = 'POST';
form.action = $1;
document.body.appendChild(form);
form.submit();)",
form_submit_url)));
form_nav_observer.Wait();
EXPECT_EQ(form_submit_url, contents()->GetLastCommittedURL());
const int64_t form_post_id =
controller.GetLastCommittedEntry()->GetPostID();
EXPECT_NE(-1, form_post_id);
EXPECT_TRUE(controller.GetLastCommittedEntry()->GetHasPostData());
EXPECT_EQ("POST", contents()->GetPrimaryMainFrame()->last_http_method());
return form_post_id;
}
void ReplaceState(FrameTreeNode* node,
const std::string& state,
GURL url = GURL()) {
FrameNavigateParamsCapturer capturer(node);
capturer.set_wait_for_load(false);
if (url.is_empty()) {
EXPECT_TRUE(
ExecJs(node, JsReplace("history.replaceState($1, '')", state)));
} else {
EXPECT_TRUE(ExecJs(
node, JsReplace("history.replaceState($1, '', $2)", state, url)));
}
capturer.Wait();
EXPECT_TRUE(capturer.is_same_document());
}
private:
base::test::ScopedFeatureList feature_list_for_render_document_;
base::test::ScopedFeatureList feature_list_for_back_forward_cache_;
};
class NavigationControllerBrowserTestNoServer
: public ContentBrowserTest,
public ::testing::WithParamInterface<
std::tuple<std::string /* render_document_level */,
bool /* enable_back_forward_cache*/>> {
public:
NavigationControllerBrowserTestNoServer() {
InitAndEnableRenderDocumentFeature(&feature_list_for_render_document_,
std::get<0>(GetParam()));
InitBackForwardCacheFeature(&feature_list_for_back_forward_cache_,
std::get<1>(GetParam()));
}
protected:
void SetUpOnMainThread() override {
host_resolver()->AddRule("*", "127.0.0.1");
content::SetupCrossSiteRedirector(embedded_test_server());
}
WebContentsImpl* contents() const {
return static_cast<WebContentsImpl*>(shell()->web_contents());
}
private:
base::test::ScopedFeatureList feature_list_for_render_document_;
base::test::ScopedFeatureList feature_list_for_back_forward_cache_;
};
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, LoadCrossSiteSubframe) {
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(1U, root->child_count());
ASSERT_NE(nullptr, root->child_at(0));
GURL foo_url(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), foo_url));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
bool cross_process = root->current_frame_host()->GetProcess() !=
root->child_at(0)->current_frame_host()->GetProcess();
EXPECT_EQ(AreAllSitesIsolatedForTesting(), cross_process);
}
void ExpectReferrerWithDefaultPolicy(FrameNavigationEntry* entry,
const GURL& url) {
EXPECT_EQ(url, entry->referrer().url);
EXPECT_EQ(blink::ReferrerUtils::MojoReferrerPolicyResolveDefault(
network::mojom::ReferrerPolicy::kDefault),
blink::ReferrerUtils::MojoReferrerPolicyResolveDefault(
entry->referrer().policy));
}
void ExpectReferrerWithDefaultPolicy(NavigationEntry* entry, const GURL& url) {
ExpectReferrerWithDefaultPolicy(
static_cast<NavigationEntryImpl*>(entry)->root_node()->frame_entry.get(),
url);
}
class LoadDataWithBaseURLWithPossiblyEmptyURLsBrowserTest
: public NavigationControllerBrowserTestBase,
public testing::WithParamInterface<
std::tuple<std::string /* render_document_level */,
bool /* use_load_data_as_string_with_base_url */,
bool /* base_url_empty */,
bool /* history_url_empty */>> {
public:
LoadDataWithBaseURLWithPossiblyEmptyURLsBrowserTest() {
InitAndEnableRenderDocumentFeature(&feature_list_for_render_document_,
std::get<0>(GetParam()));
}
static std::string DescribeParams(
const testing::TestParamInfo<ParamType>& info) {
auto [render_document_level, use_load_data_as_string_with_base_url,
base_url_empty, history_url_empty] = info.param;
return base::StringPrintf(
"%s_%s_%s_%s",
GetRenderDocumentLevelNameForTestParams(render_document_level).c_str(),
use_load_data_as_string_with_base_url ? "AsString" : "Normal",
base_url_empty ? "BaseURLEmpty" : "BaseURLSet",
history_url_empty ? "HistoryURLEmpty" : "HistoryURLSet");
}
protected:
bool use_load_data_as_string_with_base_url() {
return std::get<1>(GetParam());
}
bool base_url_empty() { return std::get<2>(GetParam()); }
bool history_url_empty() { return std::get<3>(GetParam()); }
struct URLsForLoadDataWithBaseURL {
GURL supplied_base_url;
GURL commit_url;
GURL virtual_url;
GURL history_url_for_data_url;
GURL document_url;
};
void CheckURLsMatchExpectationsForLoadDataWithBaseURL(
NavigationEntryImpl* entry,
RenderFrameHostImpl* rfh,
URLsForLoadDataWithBaseURL& urls,
bool is_renderer_initiated_same_document_navigation = false) {
EXPECT_EQ(urls.document_url, rfh->last_document_url_in_renderer());
EXPECT_EQ(urls.commit_url, entry->GetURL());
EXPECT_EQ(urls.supplied_base_url, entry->GetBaseURLForDataURL());
EXPECT_EQ(urls.history_url_for_data_url, entry->GetHistoryURLForDataURL());
EXPECT_EQ(urls.virtual_url, entry->GetVirtualURL());
EXPECT_EQ(urls.commit_url, entry->GetOriginalRequestURL());
if (!is_renderer_initiated_same_document_navigation) {
EXPECT_EQ(1u, entry->GetRedirectChain().size());
EXPECT_EQ(urls.document_url, entry->GetRedirectChain()[0]);
}
}
URLsForLoadDataWithBaseURL GetURLsForLoadDataWithBaseURL(
const GURL& commit_url,
const GURL& supplied_base_url,
const GURL& supplied_history_url) {
URLsForLoadDataWithBaseURL result;
result.supplied_base_url = supplied_base_url;
result.commit_url = commit_url;
result.virtual_url = supplied_history_url.is_empty() ? result.commit_url
: supplied_history_url;
result.history_url_for_data_url =
supplied_base_url.is_empty() ? GURL() : result.virtual_url;
result.document_url =
!supplied_base_url.is_empty() ? supplied_base_url : result.commit_url;
return result;
}
private:
base::test::ScopedFeatureList feature_list_for_render_document_;
};
IN_PROC_BROWSER_TEST_P(LoadDataWithBaseURLWithPossiblyEmptyURLsBrowserTest,
LoadDataWithBaseURLThenReload) {
#if !BUILDFLAG(IS_ANDROID)
if (use_load_data_as_string_with_base_url())
return;
#endif
if (AreAllSitesIsolatedForTesting())
return;
const std::string data_header = "data:text/html;charset=utf-8,";
const std::string title = "foo";
const std::string data = base::StringPrintf(
"<html><head><title>%s</title></head><body>foo</body></html>",
title.c_str());
const GURL data_url = GURL(data_header + data);
const GURL supplied_base_url =
base_url_empty() ? GURL() : GURL("http://baseurl");
const GURL supplied_history_url =
history_url_empty() ? GURL() : GURL("http://historyurl");
const GURL commit_url =
use_load_data_as_string_with_base_url() ? GURL(data_header) : data_url;
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
if (use_load_data_as_string_with_base_url()) {
#if BUILDFLAG(IS_ANDROID)
shell()->LoadDataAsStringWithBaseURL(supplied_history_url, data,
supplied_base_url);
#else
NOTREACHED();
#endif
} else {
shell()->LoadDataWithBaseURL(supplied_history_url, data, supplied_base_url);
}
NavigationEntryImpl* pending_entry = controller.GetPendingEntry();
URLsForLoadDataWithBaseURL urls = GetURLsForLoadDataWithBaseURL(
commit_url, supplied_base_url, supplied_history_url);
EXPECT_EQ(urls.commit_url, pending_entry->GetURL());
EXPECT_EQ(urls.supplied_base_url, pending_entry->GetBaseURLForDataURL());
EXPECT_EQ(urls.virtual_url, pending_entry->GetVirtualURL());
EXPECT_EQ(urls.history_url_for_data_url,
pending_entry->GetHistoryURLForDataURL());
same_tab_observer.Wait();
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
RenderFrameHostImpl* current_rfh =
static_cast<RenderFrameHostImpl*>(contents()->GetPrimaryMainFrame());
{
SCOPED_TRACE(testing::Message() << " Testing case 2.");
CheckURLsMatchExpectationsForLoadDataWithBaseURL(entry, current_rfh, urls);
}
EXPECT_EQ(200, current_rfh->last_http_status_code());
EXPECT_EQ(PAGE_TYPE_NORMAL, entry->GetPageType());
EXPECT_FALSE(current_rfh->IsErrorDocument());
EXPECT_EQ(entry->GetOriginalRequestURL(), urls.commit_url);
ExpectReferrerWithDefaultPolicy(entry, GURL());
ReloadBlockUntilNavigationsComplete(shell(), 1);
current_rfh =
static_cast<RenderFrameHostImpl*>(contents()->GetPrimaryMainFrame());
EXPECT_TRUE(current_rfh->IsRenderFrameLive());
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* reload_entry = controller.GetLastCommittedEntry();
EXPECT_EQ(reload_entry, entry);
{
SCOPED_TRACE(testing::Message() << " Testing case 3.");
CheckURLsMatchExpectationsForLoadDataWithBaseURL(reload_entry, current_rfh,
urls);
}
LoadDataWithBaseURL(supplied_base_url, data, supplied_history_url, title,
use_load_data_as_string_with_base_url());
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* same_url_entry = controller.GetLastCommittedEntry();
EXPECT_EQ(reload_entry, same_url_entry);
{
SCOPED_TRACE(testing::Message() << " Testing case 4.");
CheckURLsMatchExpectationsForLoadDataWithBaseURL(
same_url_entry,
static_cast<RenderFrameHostImpl*>(contents()->GetPrimaryMainFrame()),
urls);
}
}
IN_PROC_BROWSER_TEST_P(
LoadDataWithBaseURLWithPossiblyEmptyURLsBrowserTest,
HistoryNavigationWhenLoadDataWithBaseURLWithSameDocumentNavigation) {
#if !BUILDFLAG(IS_ANDROID)
if (use_load_data_as_string_with_base_url())
return;
#endif
if (AreAllSitesIsolatedForTesting())
return;
if (base_url_empty())
return;
const std::string data_header = "data:text/html;charset=utf-8,";
const std::string title = "foo";
const std::string data = base::StringPrintf(
"<html><head><title>%s</title></head><body>foo</body></html>",
title.c_str());
const GURL data_url = GURL(data_header + data);
const GURL supplied_base_url =
base_url_empty() ? GURL() : GURL("http://baseurl");
const GURL supplied_history_url =
history_url_empty() ? GURL() : GURL("http://historyurl");
const GURL commit_url =
use_load_data_as_string_with_base_url() ? GURL(data_header) : data_url;
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
LoadDataWithBaseURL(supplied_base_url, data, supplied_history_url, title,
use_load_data_as_string_with_base_url());
URLsForLoadDataWithBaseURL urls = GetURLsForLoadDataWithBaseURL(
commit_url, supplied_base_url, supplied_history_url);
CheckURLsMatchExpectationsForLoadDataWithBaseURL(
controller.GetLastCommittedEntry(),
static_cast<RenderFrameHostImpl*>(contents()->GetPrimaryMainFrame()),
urls);
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
{
FrameNavigateParamsCapturer capturer(root);
capturer.set_wait_for_load(false);
EXPECT_TRUE(ExecJs(shell(), "history.pushState({},'foo1', '#bar1')"));
capturer.Wait();
EXPECT_TRUE(capturer.is_same_document());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
CheckURLsMatchExpectationsForLoadDataWithBaseURL(
entry,
static_cast<RenderFrameHostImpl*>(contents()->GetPrimaryMainFrame()),
urls, true );
scoped_refptr<FrameNavigationEntry> frame_entry =
entry->root_node()->frame_entry.get();
if (entry->GetBaseURLForDataURL().is_empty()) {
EXPECT_TRUE(frame_entry->committed_origin()->opaque());
} else {
EXPECT_EQ(url::Origin::Create(supplied_base_url),
frame_entry->committed_origin());
}
}
{
FrameNavigateParamsCapturer capturer(root);
capturer.set_wait_for_load(false);
EXPECT_TRUE(ExecJs(shell(), "history.pushState({},'foo2', '#bar2')"));
capturer.Wait();
EXPECT_TRUE(capturer.is_same_document());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
CheckURLsMatchExpectationsForLoadDataWithBaseURL(
entry,
static_cast<RenderFrameHostImpl*>(contents()->GetPrimaryMainFrame()),
urls, true );
scoped_refptr<FrameNavigationEntry> frame_entry =
entry->root_node()->frame_entry.get();
if (entry->GetBaseURLForDataURL().is_empty()) {
EXPECT_TRUE(frame_entry->committed_origin()->opaque());
} else {
EXPECT_EQ(url::Origin::Create(supplied_base_url),
frame_entry->committed_origin());
}
}
{
FrameNavigateParamsCapturer capturer(root);
controller.GoBack();
capturer.Wait();
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
scoped_refptr<FrameNavigationEntry> frame_entry =
entry->root_node()->frame_entry.get();
if (entry->GetBaseURLForDataURL().is_empty()) {
EXPECT_TRUE(frame_entry->committed_origin()->opaque());
} else {
EXPECT_EQ(url::Origin::Create(supplied_base_url),
frame_entry->committed_origin());
}
}
}
IN_PROC_BROWSER_TEST_P(LoadDataWithBaseURLWithPossiblyEmptyURLsBrowserTest,
LoadDataWithBaseURLThenRendererInitiatedSameDocument) {
#if !BUILDFLAG(IS_ANDROID)
if (use_load_data_as_string_with_base_url())
return;
#endif
if (AreAllSitesIsolatedForTesting())
return;
if (base_url_empty())
return;
const std::string data_header = "data:text/html;charset=utf-8,";
const std::string title = "foo";
const std::string data = base::StringPrintf(
"<html><head><title>%s</title></head><body>foo</body></html>",
title.c_str());
const GURL data_url = GURL(data_header + data);
const GURL supplied_base_url =
base_url_empty() ? GURL() : GURL("http://baseurl");
const GURL supplied_history_url =
history_url_empty() ? GURL() : GURL("http://historyurl");
const GURL commit_url =
use_load_data_as_string_with_base_url() ? GURL(data_header) : data_url;
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
LoadDataWithBaseURL(supplied_base_url, data, supplied_history_url, title,
use_load_data_as_string_with_base_url());
URLsForLoadDataWithBaseURL urls = GetURLsForLoadDataWithBaseURL(
commit_url, supplied_base_url, supplied_history_url);
CheckURLsMatchExpectationsForLoadDataWithBaseURL(
controller.GetLastCommittedEntry(),
static_cast<RenderFrameHostImpl*>(contents()->GetPrimaryMainFrame()),
urls);
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
{
SCOPED_TRACE(testing::Message() << " Testing case 2.");
FrameNavigateParamsCapturer capturer(root);
capturer.set_wait_for_load(false);
GURL document_url_with_fragment = GURL(urls.document_url.spec() + "#foo");
EXPECT_TRUE(ExecJs(
shell(), JsReplace("location.href = $1;", document_url_with_fragment)));
capturer.Wait();
EXPECT_TRUE(capturer.is_same_document());
CheckURLsMatchExpectationsForLoadDataWithBaseURL(
controller.GetLastCommittedEntry(),
static_cast<RenderFrameHostImpl*>(contents()->GetPrimaryMainFrame()),
urls, true );
}
{
SCOPED_TRACE(testing::Message() << " Testing case 3.");
FrameNavigateParamsCapturer capturer(root);
capturer.set_wait_for_load(false);
EXPECT_TRUE(ExecJs(shell(), "history.pushState({},'foo', 'bar')"));
capturer.Wait();
EXPECT_TRUE(capturer.is_same_document());
CheckURLsMatchExpectationsForLoadDataWithBaseURL(
controller.GetLastCommittedEntry(),
static_cast<RenderFrameHostImpl*>(contents()->GetPrimaryMainFrame()),
urls, true );
}
}
IN_PROC_BROWSER_TEST_P(LoadDataWithBaseURLWithPossiblyEmptyURLsBrowserTest,
LoadDataWithBaseURLThenBrowserInitiatedSameDocument) {
#if !BUILDFLAG(IS_ANDROID)
if (use_load_data_as_string_with_base_url())
return;
#endif
if (AreAllSitesIsolatedForTesting())
return;
const std::string data_header = "data:text/html;charset=utf-8,";
const std::string title = "foo";
const std::string data = base::StringPrintf(
"<html><head><title>%s</title></head><body>foo</body></html>",
title.c_str());
const GURL data_url = GURL(data_header + data);
const GURL supplied_base_url =
base_url_empty() ? GURL()
: embedded_test_server()->GetURL("/title1.html");
const GURL supplied_history_url =
history_url_empty() ? GURL()
: embedded_test_server()->GetURL("/title2.html");
const GURL commit_url =
use_load_data_as_string_with_base_url() ? GURL(data_header) : data_url;
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
LoadDataWithBaseURL(supplied_base_url, data, supplied_history_url, title,
use_load_data_as_string_with_base_url());
URLsForLoadDataWithBaseURL urls = GetURLsForLoadDataWithBaseURL(
commit_url, supplied_base_url, supplied_history_url);
CheckURLsMatchExpectationsForLoadDataWithBaseURL(
controller.GetLastCommittedEntry(),
static_cast<RenderFrameHostImpl*>(contents()->GetPrimaryMainFrame()),
urls);
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
{
SCOPED_TRACE(testing::Message() << " Testing case 1. ");
FrameNavigateParamsCapturer capturer(root);
capturer.set_wait_for_load(false);
GURL commit_url_with_fragment = GURL(commit_url.spec() + "#foo");
NavigationController::LoadURLParams params(commit_url_with_fragment);
params.transition_type = ui::PageTransitionFromInt(
ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
contents()->GetController().LoadURLWithParams(params);
capturer.Wait();
EXPECT_EQ(urls.document_url == urls.commit_url,
capturer.is_same_document());
urls.commit_url = commit_url_with_fragment;
urls.document_url = commit_url_with_fragment;
urls.history_url_for_data_url = GURL();
urls.supplied_base_url = GURL();
urls.virtual_url = (capturer.is_same_document() && !history_url_empty())
? supplied_history_url
: commit_url_with_fragment;
CheckURLsMatchExpectationsForLoadDataWithBaseURL(
controller.GetLastCommittedEntry(),
static_cast<RenderFrameHostImpl*>(contents()->GetPrimaryMainFrame()),
urls);
}
LoadDataWithBaseURL(supplied_base_url, data, supplied_history_url, title,
use_load_data_as_string_with_base_url());
urls = GetURLsForLoadDataWithBaseURL(commit_url, supplied_base_url,
supplied_history_url);
CheckURLsMatchExpectationsForLoadDataWithBaseURL(
controller.GetLastCommittedEntry(),
static_cast<RenderFrameHostImpl*>(contents()->GetPrimaryMainFrame()),
urls);
{
SCOPED_TRACE(testing::Message() << " Testing case 2. ");
FrameNavigateParamsCapturer capturer(root);
capturer.set_wait_for_load(false);
GURL document_url_with_fragment = GURL(urls.document_url.spec() + "#foo");
NavigationController::LoadURLParams params(document_url_with_fragment);
params.transition_type = ui::PageTransitionFromInt(
ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
contents()->GetController().LoadURLWithParams(params);
capturer.Wait();
EXPECT_EQ(urls.document_url == urls.commit_url,
capturer.is_same_document());
urls.commit_url = document_url_with_fragment;
urls.document_url = document_url_with_fragment;
urls.history_url_for_data_url = GURL();
urls.supplied_base_url = GURL();
urls.virtual_url = (capturer.is_same_document() && !history_url_empty())
? supplied_history_url
: document_url_with_fragment;
CheckURLsMatchExpectationsForLoadDataWithBaseURL(
controller.GetLastCommittedEntry(),
static_cast<RenderFrameHostImpl*>(contents()->GetPrimaryMainFrame()),
urls);
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
LoadDataWithBaseURLThenHistoryNavigationInSubframe) {
if (AreAllSitesIsolatedForTesting())
return;
GURL subframe_url_1(embedded_test_server()->GetURL(
"a.com", "/navigation_controller/simple_page.html"));
GURL subframe_url_2(embedded_test_server()->GetURL(
"b.com", "/navigation_controller/simple_page_1.html"));
const std::string data =
base::StringPrintf("<html><body><iframe src=\"%s\"/></body></html>",
subframe_url_1.spec().c_str());
const GURL base_url = GURL("http://baseurl");
const GURL history_url = GURL("http://historyurl");
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
{
TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
shell()->LoadDataWithBaseURL(history_url, data, base_url);
same_tab_observer.Wait();
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
scoped_refptr<FrameNavigationEntry> subframe_entry =
entry->root_node()->children[0]->frame_entry.get();
EXPECT_EQ(url::Origin::Create(subframe_url_1),
subframe_entry->committed_origin());
EXPECT_EQ(subframe_url_1, subframe_entry->url());
}
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
std::string script = "history.pushState({}, 'page 1', '#bar1')";
EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(capturer.is_same_document());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
scoped_refptr<FrameNavigationEntry> main_frame_entry =
entry->root_node()->frame_entry.get();
EXPECT_EQ(url::Origin::Create(base_url),
main_frame_entry->committed_origin());
scoped_refptr<FrameNavigationEntry> subframe_entry =
entry->root_node()->children[0]->frame_entry.get();
EXPECT_EQ(url::Origin::Create(subframe_url_1),
subframe_entry->committed_origin());
EXPECT_EQ(subframe_url_1.spec() + "#bar1", subframe_entry->url());
}
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), subframe_url_2));
capturer.Wait();
EXPECT_FALSE(capturer.is_same_document());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
scoped_refptr<FrameNavigationEntry> main_frame_entry =
entry->root_node()->frame_entry.get();
EXPECT_EQ(url::Origin::Create(base_url),
main_frame_entry->committed_origin());
scoped_refptr<FrameNavigationEntry> subframe_entry =
entry->root_node()->children[0]->frame_entry.get();
EXPECT_EQ(url::Origin::Create(subframe_url_2),
subframe_entry->committed_origin());
EXPECT_EQ(subframe_url_2, subframe_entry->url());
}
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
std::string script = "history.back()";
EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_FALSE(capturer.is_same_document());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
scoped_refptr<FrameNavigationEntry> main_frame_entry =
entry->root_node()->frame_entry.get();
EXPECT_EQ(url::Origin::Create(base_url),
main_frame_entry->committed_origin());
scoped_refptr<FrameNavigationEntry> subframe_entry =
entry->root_node()->children[0]->frame_entry.get();
EXPECT_EQ(url::Origin::Create(subframe_url_1),
subframe_entry->committed_origin());
EXPECT_EQ(subframe_url_1.spec() + "#bar1", subframe_entry->url());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
LoadDataWithBaseURLTitleAfterBack) {
if (AreAllSitesIsolatedForTesting())
return;
const GURL base_url("http://baseurl");
const GURL history_url(
embedded_test_server()->GetURL("/navigation_controller/form.html"));
const std::string data1 = "<html><title>One</title><body>foo</body></html>";
const GURL data_url1 = GURL("data:text/html;charset=utf-8," + data1);
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
{
TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
shell()->LoadDataWithBaseURL(history_url, data1, base_url);
same_tab_observer.Wait();
}
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
EXPECT_EQ(history_url, entry->GetVirtualURL());
EXPECT_EQ(history_url, entry->GetHistoryURLForDataURL());
EXPECT_EQ(data_url1, entry->GetURL());
EXPECT_EQ("http://baseurl", EvalJs(shell(), "self.origin"));
EXPECT_EQ(
url::Origin::Create(base_url),
shell()->web_contents()->GetPrimaryMainFrame()->GetLastCommittedOrigin());
const std::string data2 = "<html><title>Two</title><body>bar</body></html>";
const GURL data_url2 = GURL("data:text/html;charset=utf-8," + data2);
{
TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
EXPECT_TRUE(NavigateToURL(shell(), data_url2));
same_tab_observer.Wait();
}
url::Origin data_origin =
shell()->web_contents()->GetPrimaryMainFrame()->GetLastCommittedOrigin();
EXPECT_TRUE(data_origin.opaque());
EXPECT_EQ(url::SchemeHostPort(),
data_origin.GetTupleOrPrecursorTupleIfOpaque());
TestNavigationObserver back_load_observer(shell()->web_contents());
controller.GoBack();
back_load_observer.Wait();
EXPECT_EQ("One", base::UTF16ToUTF8(shell()->web_contents()->GetTitle()));
NavigationEntryImpl* back_entry = controller.GetLastCommittedEntry();
EXPECT_EQ(base_url, back_entry->GetBaseURLForDataURL());
EXPECT_EQ(history_url, back_entry->GetVirtualURL());
EXPECT_EQ(history_url, back_entry->GetHistoryURLForDataURL());
EXPECT_EQ(data_url1, back_entry->GetOriginalRequestURL());
EXPECT_EQ(data_url1, back_entry->GetURL());
EXPECT_EQ(
data_url1,
shell()->web_contents()->GetPrimaryMainFrame()->GetLastCommittedURL());
EXPECT_EQ(
url::Origin::Create(base_url),
shell()->web_contents()->GetPrimaryMainFrame()->GetLastCommittedOrigin());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
CrossDomainResourceRequestLoadDataWithBaseUrl) {
const GURL base_url("foobar://");
const GURL history_url("http://historyurl");
const std::string data = "<html><body></body></html>";
const GURL data_url = GURL("data:text/html;charset=utf-8," + data);
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
{
TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
shell()->LoadDataWithBaseURL(history_url, data, base_url);
same_tab_observer.Wait();
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
EXPECT_EQ(history_url, entry->GetVirtualURL());
EXPECT_EQ(history_url, entry->GetHistoryURLForDataURL());
EXPECT_EQ(data_url, entry->GetURL());
}
std::string script =
"var url = 'http://www.example.com';\n"
"var xhr = new XMLHttpRequest();\n"
"xhr.open('GET', url);\n"
"xhr.send();\n";
EXPECT_TRUE(ExecJs(shell()->web_contents(), script));
ReloadBlockUntilNavigationsComplete(shell(), 1);
EXPECT_TRUE(
shell()->web_contents()->GetPrimaryMainFrame()->IsRenderFrameLive());
}
class LoadDataWithBaseURLBrowserTest
: public NavigationControllerBrowserTestBase,
public testing::WithParamInterface<
std::tuple<std::string /* render_document_level */,
bool /* use_load_data_as_string_with_base_url */>> {
public:
LoadDataWithBaseURLBrowserTest() {
InitAndEnableRenderDocumentFeature(&feature_list_for_render_document_,
std::get<0>(GetParam()));
}
static std::string DescribeParams(
const testing::TestParamInfo<ParamType>& info) {
auto [render_document_level, use_load_data_as_string_with_base_url] =
info.param;
return base::StringPrintf(
"%s_%s",
GetRenderDocumentLevelNameForTestParams(render_document_level).c_str(),
use_load_data_as_string_with_base_url ? "AsString" : "Normal");
}
protected:
bool use_load_data_as_string_with_base_url() {
return std::get<1>(GetParam());
}
private:
base::test::ScopedFeatureList feature_list_for_render_document_;
};
IN_PROC_BROWSER_TEST_P(LoadDataWithBaseURLBrowserTest,
LoadDataWithInvalidBaseURL) {
#if !BUILDFLAG(IS_ANDROID)
if (use_load_data_as_string_with_base_url())
return;
#endif
if (AreAllSitesIsolatedForTesting())
return;
const GURL base_url("http://");
const GURL history_url("http://historyurl");
const std::string title = "invalid_base_url";
const std::string data = base::StringPrintf(
"<html><head><title>%s</title></head><body>foo</body></html>",
title.c_str());
LoadDataWithBaseURL(base_url, data, history_url, title,
use_load_data_as_string_with_base_url());
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
const GURL original_committed_url =
contents()->GetPrimaryMainFrame()->GetLastCommittedURL();
{
TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
EXPECT_TRUE(ExecJs(shell(), "history.pushState('', 'test', '#foo')"));
same_tab_observer.Wait();
}
EXPECT_EQ(2, controller.GetEntryCount());
entry = controller.GetLastCommittedEntry();
EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
EXPECT_EQ(original_committed_url.spec() + "#foo",
contents()->GetPrimaryMainFrame()->GetLastCommittedURL());
EXPECT_EQ(PAGE_TYPE_NORMAL, entry->GetPageType());
EXPECT_FALSE(contents()->GetPrimaryMainFrame()->IsErrorDocument());
}
class BlockAllCommitContentBrowserClient
: public ContentBrowserTestContentBrowserClient {
public:
BlockAllCommitContentBrowserClient() = default;
BlockAllCommitContentBrowserClient(
const BlockAllCommitContentBrowserClient&) = delete;
BlockAllCommitContentBrowserClient& operator=(
const BlockAllCommitContentBrowserClient&) = delete;
bool CanCommitURL(RenderProcessHost* process_host,
const GURL& site_url) override {
return false;
}
};
IN_PROC_BROWSER_TEST_P(LoadDataWithBaseURLBrowserTest,
LoadDataWithBlockedDataURL) {
#if !BUILDFLAG(IS_ANDROID)
if (use_load_data_as_string_with_base_url())
return;
#endif
if (AreAllSitesIsolatedForTesting())
return;
BlockAllCommitContentBrowserClient content_browser_client;
const GURL base_url = embedded_test_server()->GetURL("/title1.html");
const GURL history_url("http://historyurl");
const std::string title = "blocked_url";
const std::string data = base::StringPrintf(
"<html><head><title>%s</title></head><body>foo</body></html>",
title.c_str());
LoadDataWithBaseURL(base_url, data, history_url, title,
use_load_data_as_string_with_base_url());
const GURL data_url = GURL("data:text/html;charset=utf-8," + data);
const GURL commit_url = use_load_data_as_string_with_base_url()
? GURL("data:text/html;charset=utf-8,")
: data_url;
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
EXPECT_EQ(commit_url,
contents()->GetPrimaryMainFrame()->GetLastCommittedURL());
EXPECT_EQ(PAGE_TYPE_NORMAL, entry->GetPageType());
EXPECT_FALSE(contents()->GetPrimaryMainFrame()->IsErrorDocument());
{
TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
EXPECT_TRUE(ExecJs(shell(), "history.pushState('', 'test', '#foo')"));
same_tab_observer.Wait();
}
EXPECT_EQ(2, controller.GetEntryCount());
entry = controller.GetLastCommittedEntry();
EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
EXPECT_EQ(commit_url,
contents()->GetPrimaryMainFrame()->GetLastCommittedURL());
{
TestNavigationObserver back_load_observer(shell()->web_contents());
controller.GoBack();
back_load_observer.Wait();
}
EXPECT_EQ(2, controller.GetEntryCount());
entry = controller.GetLastCommittedEntry();
EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
EXPECT_EQ(commit_url,
contents()->GetPrimaryMainFrame()->GetLastCommittedURL());
EXPECT_EQ(PAGE_TYPE_NORMAL, entry->GetPageType());
EXPECT_FALSE(contents()->GetPrimaryMainFrame()->IsErrorDocument());
{
TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
EXPECT_TRUE(ExecJs(shell(), "location.href = '#bar';"));
same_tab_observer.Wait();
}
EXPECT_EQ(2, controller.GetEntryCount());
entry = controller.GetLastCommittedEntry();
EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
EXPECT_EQ(commit_url,
contents()->GetPrimaryMainFrame()->GetLastCommittedURL());
EXPECT_EQ(PAGE_TYPE_NORMAL, entry->GetPageType());
EXPECT_FALSE(contents()->GetPrimaryMainFrame()->IsErrorDocument());
}
IN_PROC_BROWSER_TEST_P(LoadDataWithBaseURLBrowserTest,
LoadDataWithBlockedDataURLAndInvalidBaseURL) {
#if !BUILDFLAG(IS_ANDROID)
if (use_load_data_as_string_with_base_url())
return;
#endif
if (AreAllSitesIsolatedForTesting())
return;
const GURL base_url("http://");
EXPECT_TRUE(!base_url.is_valid());
const GURL history_url("http://historyurl");
const std::string title = "invalid_base_url";
const std::string data = base::StringPrintf(
"<html><head><title>%s</title></head><body>foo</body></html>",
title.c_str());
BlockAllCommitContentBrowserClient content_browser_client;
RenderProcessHostBadIpcMessageWaiter kill_waiter(
shell()->web_contents()->GetPrimaryMainFrame()->GetProcess());
if (use_load_data_as_string_with_base_url()) {
#if BUILDFLAG(IS_ANDROID)
shell()->LoadDataAsStringWithBaseURL(history_url, data, base_url);
#else
NOTREACHED();
#endif
} else {
shell()->LoadDataWithBaseURL(history_url, data, base_url);
}
EXPECT_EQ(bad_message::RFH_CAN_COMMIT_URL_BLOCKED, kill_waiter.Wait());
}
IN_PROC_BROWSER_TEST_P(
LoadDataWithBaseURLBrowserTest,
LoadDataWithBaseURLThenJavaScriptURLThenSameDocumentNavigation) {
#if !BUILDFLAG(IS_ANDROID)
if (use_load_data_as_string_with_base_url())
return;
#endif
if (AreAllSitesIsolatedForTesting())
return;
const GURL base_url("http://baseurl");
const GURL history_url("http://history");
const std::string title = "foo";
const std::string data_header = "data:text/html;charset=utf-8,";
const std::string data = base::StringPrintf(
"<html><head><title>%s</title></head><body>foo</body></html>",
title.c_str());
const GURL data_url = GURL(data_header + data);
const GURL commit_url =
use_load_data_as_string_with_base_url() ? GURL(data_header) : data_url;
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
LoadDataWithBaseURL(base_url, data, history_url, title,
use_load_data_as_string_with_base_url());
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
EXPECT_EQ(history_url, entry->GetVirtualURL());
EXPECT_EQ(history_url, entry->GetHistoryURLForDataURL());
EXPECT_EQ(commit_url, entry->GetURL());
EXPECT_EQ(commit_url,
contents()->GetPrimaryMainFrame()->GetLastCommittedURL());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
const int64_t start_dsn = controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number();
EXPECT_TRUE(ExecJs(root, R"(window.location = 'javascript:"foo"';)"));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(
use_load_data_as_string_with_base_url() ? GURL(data_header) : data_url,
root->current_url());
EXPECT_EQ("foo", EvalJs(shell(), "document.body.innerHTML"));
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(200, contents()->GetPrimaryMainFrame()->last_http_status_code());
EXPECT_EQ(start_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number());
{
TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
EXPECT_TRUE(ExecJs(shell(), "history.pushState('', 'test', '#foo')"));
same_tab_observer.Wait();
}
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_NE(entry, controller.GetLastCommittedEntry());
entry = controller.GetLastCommittedEntry();
EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
EXPECT_EQ(history_url, entry->GetVirtualURL());
EXPECT_EQ(history_url, entry->GetHistoryURLForDataURL());
EXPECT_EQ(commit_url, entry->GetURL());
EXPECT_EQ(commit_url,
contents()->GetPrimaryMainFrame()->GetLastCommittedURL().spec());
EXPECT_EQ(start_dsn, entry->GetFrameEntry(root)->document_sequence_number());
{
TestNavigationObserver back_load_observer(shell()->web_contents());
controller.GoBack();
back_load_observer.Wait();
}
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_NE(entry, controller.GetLastCommittedEntry());
entry = controller.GetLastCommittedEntry();
EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
EXPECT_EQ(history_url, entry->GetVirtualURL());
EXPECT_EQ(history_url, entry->GetHistoryURLForDataURL());
EXPECT_EQ(commit_url,
contents()->GetPrimaryMainFrame()->GetLastCommittedURL());
EXPECT_EQ(start_dsn, entry->GetFrameEntry(root)->document_sequence_number());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
ErrorPageFromLoadDataWithBaseURL) {
if (AreAllSitesIsolatedForTesting())
return;
const GURL base_url("http://baseurl");
const GURL history_url("http://historyurl");
const std::string data = "<html><body></body></html>";
const GURL data_url = GURL("data:text/html;charset=utf-8," + data);
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
auto url_loader_interceptor = std::make_unique<URLLoaderInterceptor>(
base::BindRepeating([](URLLoaderInterceptor::RequestParams* params) {
network::URLLoaderCompletionStatus status;
status.error_code = net::ERR_NOT_IMPLEMENTED;
params->client->OnComplete(status);
return true;
}));
{
TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
shell()->LoadDataWithBaseURL(history_url, data, base_url);
same_tab_observer.Wait();
EXPECT_FALSE(same_tab_observer.last_navigation_succeeded());
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
EXPECT_TRUE(contents()->GetPrimaryMainFrame()->IsErrorDocument());
EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
EXPECT_EQ(history_url, entry->GetVirtualURL());
EXPECT_EQ(history_url, entry->GetHistoryURLForDataURL());
EXPECT_EQ(data_url, entry->GetURL());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
NavigateFromLoadDataWithBaseURL) {
if (AreAllSitesIsolatedForTesting())
return;
const GURL base_url("http://baseurl");
const GURL history_url("http://historyurl");
const std::string data = "<html><body></body></html>";
const GURL data_url = GURL("data:text/html;charset=utf-8," + data);
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
{
TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
shell()->LoadDataWithBaseURL(history_url, data, base_url);
same_tab_observer.Wait();
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
EXPECT_EQ(history_url, entry->GetVirtualURL());
EXPECT_EQ(history_url, entry->GetHistoryURLForDataURL());
EXPECT_EQ(data_url, entry->GetURL());
}
{
GURL navigate_url = embedded_test_server()->GetURL("/title1.html");
std::string script = JsReplace("document.location = $1", navigate_url);
TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
EXPECT_TRUE(ExecJs(shell(), script));
same_tab_observer.Wait();
EXPECT_EQ(2, controller.GetEntryCount());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_TRUE(entry->GetBaseURLForDataURL().is_empty());
EXPECT_TRUE(entry->GetHistoryURLForDataURL().is_empty());
EXPECT_EQ(navigate_url, entry->GetVirtualURL());
EXPECT_EQ(navigate_url, entry->GetURL());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FragmentNavigateFromLoadDataWithBaseURL) {
if (AreAllSitesIsolatedForTesting())
return;
const GURL base_url("http://baseurl");
const GURL history_url("http://historyurl");
const std::string data =
"<html><body>"
" <p id=\"frag\">"
" <a id=\"fraglink\" href=\"#frag\">same document nav</a>"
" </p>"
"</body></html>";
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
#if BUILDFLAG(IS_ANDROID)
shell()->LoadDataAsStringWithBaseURL(history_url, data, base_url);
#else
shell()->LoadDataWithBaseURL(history_url, data, base_url);
#endif
same_tab_observer.Wait();
EXPECT_EQ(1, controller.GetEntryCount());
const GURL data_url = controller.GetLastCommittedEntry()->GetURL();
GURL js_url("javascript:document.location = '#frag';");
EXPECT_FALSE(NavigateToURL(shell(), js_url));
EXPECT_EQ(2, controller.GetEntryCount());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
EXPECT_EQ(history_url, entry->GetHistoryURLForDataURL());
EXPECT_EQ(history_url, entry->GetVirtualURL());
EXPECT_EQ(data_url, entry->GetURL());
EXPECT_TRUE(ExecJs(shell(), "console.log('Success');"));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, UniqueIDs) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_link_to_load_iframe.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
ASSERT_EQ(1, controller.GetEntryCount());
std::string script = "document.getElementById('link').click()";
EXPECT_TRUE(ExecJs(shell(), script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
ASSERT_EQ(2, controller.GetEntryCount());
ASSERT_NE(controller.GetEntryAtIndex(0)->GetUniqueID(),
controller.GetEntryAtIndex(1)->GetUniqueID());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, UniqueIDsOnFrames) {
NavigationController& controller = shell()->web_contents()->GetController();
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(1U, root->child_count());
ASSERT_NE(nullptr, root->child_at(0));
int unique_id = controller.GetLastCommittedEntry()->GetUniqueID();
EXPECT_EQ(unique_id, root->current_frame_host()->nav_entry_id());
EXPECT_EQ(unique_id, root->child_at(0)->current_frame_host()->nav_entry_id());
GURL foo_url(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), foo_url));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(unique_id, controller.GetLastCommittedEntry()->GetUniqueID());
EXPECT_EQ(unique_id, root->current_frame_host()->nav_entry_id());
EXPECT_EQ(unique_id, root->child_at(0)->current_frame_host()->nav_entry_id());
GURL foo_url2(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_2.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), foo_url2));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
int unique_id2 = controller.GetLastCommittedEntry()->GetUniqueID();
EXPECT_NE(unique_id, unique_id2);
EXPECT_EQ(unique_id2, root->current_frame_host()->nav_entry_id());
EXPECT_EQ(unique_id2,
root->child_at(0)->current_frame_host()->nav_entry_id());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
DontIgnoreBackAfterNavEntryLimit) {
NavigationController& controller = shell()->web_contents()->GetController();
NavigationControllerImpl::set_max_entry_count_for_testing(10);
const int kMaxEntryCount =
static_cast<int>(NavigationControllerImpl::max_entry_count());
for (int url_index = 0; url_index < kMaxEntryCount; ++url_index) {
GURL url(base::StringPrintf("data:text/html,page%d", url_index));
EXPECT_TRUE(NavigateToURL(shell(), url));
}
EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
for (int url_index = kMaxEntryCount; url_index < kMaxEntryCount + 2;
++url_index) {
GURL url(base::StringPrintf("data:text/html,page%d", url_index));
EXPECT_TRUE(NavigateToURL(shell(), url));
}
EXPECT_EQ(kMaxEntryCount, controller.GetEntryCount());
EXPECT_EQ(GURL("data:text/html,page2"),
controller.GetEntryAtIndex(0)->GetURL());
ASSERT_TRUE(controller.CanGoBack());
controller.GoBack();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(GURL(base::StringPrintf("data:text/html,page%d", kMaxEntryCount)),
controller.GetLastCommittedEntry()->GetURL());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
DontIgnoreRendererInitiatedBackAfterNavEntryLimit) {
NavigationController& controller = shell()->web_contents()->GetController();
NavigationControllerImpl::set_max_entry_count_for_testing(10);
const int kMaxEntryCount =
static_cast<int>(NavigationControllerImpl::max_entry_count());
for (int url_index = 0; url_index < kMaxEntryCount; ++url_index) {
GURL url(base::StringPrintf("data:text/html,page%d", url_index));
EXPECT_TRUE(NavigateToURL(shell(), url));
}
EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
for (int url_index = kMaxEntryCount; url_index < kMaxEntryCount + 2;
++url_index) {
GURL url(base::StringPrintf("data:text/html,page%d", url_index));
EXPECT_TRUE(NavigateToURL(shell(), url));
}
EXPECT_EQ(kMaxEntryCount, controller.GetEntryCount());
EXPECT_EQ(GURL("data:text/html,page2"),
controller.GetEntryAtIndex(0)->GetURL());
ASSERT_TRUE(controller.CanGoBack());
{
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "history.back()"));
capturer.Wait();
}
EXPECT_EQ(GURL(base::StringPrintf("data:text/html,page%d", kMaxEntryCount)),
controller.GetLastCommittedEntry()->GetURL());
}
namespace {
bool RendererLocationReplace(Shell* shell, const GURL& url) {
WebContents* web_contents = shell->web_contents();
WaitForLoadStop(web_contents);
TestNavigationManager navigation_manager(web_contents, url);
const GURL& current_url =
web_contents->GetPrimaryMainFrame()->GetLastCommittedURL();
EXPECT_TRUE(ExecJs(shell, JsReplace("window.location.replace($1)", url),
EXECUTE_SCRIPT_DEFAULT_OPTIONS, 1));
if (!current_url.EqualsIgnoringRef(url)) {
EXPECT_TRUE(navigation_manager.WaitForRequestStart());
EXPECT_TRUE(
NavigationRequest::From(navigation_manager.GetNavigationHandle())
->common_params()
.should_replace_current_entry);
}
EXPECT_TRUE(navigation_manager.WaitForNavigationFinished());
if (!IsLastCommittedEntryOfPageType(web_contents, PAGE_TYPE_NORMAL))
return false;
return web_contents->GetLastCommittedURL() == url;
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
CorrectLengthWithCurrentItemReplacement) {
NavigationController& controller = shell()->web_contents()->GetController();
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL("/simple_page.html")));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(1, EvalJs(shell(), "history.length"));
EXPECT_TRUE(RendererLocationReplace(
shell(), embedded_test_server()->GetURL("/title1.html")));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(1, EvalJs(shell(), "history.length"));
EXPECT_TRUE(
NavigateToURL(shell(), embedded_test_server()->GetURL("/title2.html")));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(2, EvalJs(shell(), "history.length"));
EXPECT_TRUE(
NavigateToURL(shell(), embedded_test_server()->GetURL("/title3.html")));
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(3, EvalJs(shell(), "history.length"));
controller.GoBack();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
controller.GoBack();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_TRUE(controller.CanGoForward());
EXPECT_TRUE(RendererLocationReplace(
shell(), embedded_test_server()->GetURL("/simple_page.html?page1b")));
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(3, EvalJs(shell(), "history.length"));
EXPECT_TRUE(controller.CanGoForward());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
CorrectLengthWithNewTabNavigatingFromWebUI) {
GURL web_ui_page(std::string(kChromeUIScheme) + "://" +
std::string(kChromeUIGpuHost));
EXPECT_TRUE(NavigateToURL(shell(), web_ui_page));
EXPECT_EQ(
BINDINGS_POLICY_WEB_UI,
shell()->web_contents()->GetPrimaryMainFrame()->GetEnabledBindings());
ShellAddedObserver observer;
GURL page_url = embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html");
EXPECT_TRUE(ExecJs(shell(), JsReplace("window.open($1, '_blank');", page_url),
EXECUTE_SCRIPT_DEFAULT_OPTIONS, 1));
Shell* shell2 = observer.GetShell();
EXPECT_TRUE(WaitForLoadStop(shell2->web_contents()));
EXPECT_EQ(1, shell2->web_contents()->GetController().GetEntryCount());
EXPECT_EQ(1, EvalJs(shell2, "history.length", EXECUTE_SCRIPT_DEFAULT_OPTIONS,
1));
}
namespace {
class NoNavigationsObserver : public WebContentsObserver {
public:
explicit NoNavigationsObserver(WebContents* web_contents)
: WebContentsObserver(web_contents) {}
private:
void DidFinishNavigation(NavigationHandle* navigation_handle) override {
if (!navigation_handle->HasCommitted())
return;
FAIL() << "No navigations should occur";
}
};
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
NavigateBackInChildOfLoadDataWithBaseURL) {
if (AreAllSitesIsolatedForTesting())
return;
GURL iframe_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_links.html"));
const GURL base_url("http://baseurl");
const GURL history_url("http://historyurl");
std::string data =
"<html><body>"
" <p>"
" <iframe src=\"";
data += iframe_url.spec();
data +=
"\" />"
" </p>"
"</body></html>";
TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
#if BUILDFLAG(IS_ANDROID)
shell()->LoadDataAsStringWithBaseURL(history_url, data, base_url);
#else
shell()->LoadDataWithBaseURL(history_url, data, base_url);
#endif
same_tab_observer.Wait();
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(1u, root->child_count());
FrameTreeNode* child = root->child_at(0u);
{
TestNavigationObserver observer(shell()->web_contents(), 1);
std::string script = "document.getElementById('thelink').click()";
EXPECT_TRUE(ExecJs(child, script));
observer.Wait();
}
{
TestNavigationObserver observer(shell()->web_contents(), 1);
shell()->web_contents()->GetController().GoBack();
observer.Wait();
}
EXPECT_TRUE(ExecJs(shell(), "console.log('Success');"));
}
class LoadCommittedCapturer : public WebContentsObserver {
public:
explicit LoadCommittedCapturer(FrameTreeNode* node)
: WebContentsObserver(
WebContents::FromRenderFrameHost(node->current_frame_host())),
frame_tree_node_id_(node->frame_tree_node_id()),
message_loop_runner_(new MessageLoopRunner) {}
explicit LoadCommittedCapturer(WebContents* web_contents)
: WebContentsObserver(web_contents),
frame_tree_node_id_(0),
message_loop_runner_(new MessageLoopRunner) {}
void Wait() { message_loop_runner_->Run(); }
ui::PageTransition transition_type() const { return transition_type_; }
private:
void RenderFrameCreated(RenderFrameHost* render_frame_host) override {
RenderFrameHostImpl* rfh =
static_cast<RenderFrameHostImpl*>(render_frame_host);
if (rfh->IsPendingDeletion()) {
DLOG(INFO) << "Skipping pending delete RFH: "
<< rfh->GetSiteInstance()->GetSiteURL();
return;
}
int frame_tree_node_id = rfh->frame_tree_node()->frame_tree_node_id();
DCHECK(frame_tree_node_id_ == 0 ||
frame_tree_node_id_ == frame_tree_node_id);
frame_tree_node_id_ = frame_tree_node_id;
}
void DidFinishNavigation(NavigationHandle* navigation_handle) override {
if (!navigation_handle->HasCommitted())
return;
DCHECK_NE(0, frame_tree_node_id_);
if (navigation_handle->GetRenderFrameHost()->GetFrameTreeNodeId() !=
frame_tree_node_id_) {
return;
}
transition_type_ = navigation_handle->GetPageTransition();
if (!web_contents()->IsLoading())
message_loop_runner_->Quit();
}
void DidStopLoading() override { message_loop_runner_->Quit(); }
int frame_tree_node_id_;
ui::PageTransition transition_type_;
scoped_refptr<MessageLoopRunner> message_loop_runner_;
};
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, SubframeOnEmptyPage) {
EXPECT_TRUE(NavigateToURL(shell(), GURL(url::kAboutBlankURL)));
Shell* new_shell = OpenBlankWindow(contents());
FrameTreeNode* new_root =
static_cast<WebContentsImpl*>(new_shell->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_TRUE(new_shell->web_contents()
->GetController()
.GetLastCommittedEntry()
->IsInitialEntry());
{
LoadCommittedCapturer capturer(new_shell->web_contents());
std::string script =
JsReplace(kAddFrameWithSrcScript, "data:text/html,<p>some page</p>");
EXPECT_TRUE(ExecJs(new_root, script));
capturer.Wait();
}
ASSERT_EQ(1U, new_root->child_count());
ASSERT_NE(nullptr, new_root->child_at(0));
EXPECT_TRUE(
static_cast<NavigationEntryImpl*>(
new_shell->web_contents()->GetController().GetLastCommittedEntry())
->GetFrameEntry(new_root->child_at(0)));
GURL frame_url = embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_2.html");
{
LoadCommittedCapturer capturer(new_root->child_at(0));
std::string script = JsReplace("location.assign($1);", frame_url);
EXPECT_TRUE(ExecJs(new_root->child_at(0), script));
capturer.Wait();
}
EXPECT_TRUE(
static_cast<NavigationEntryImpl*>(
new_shell->web_contents()->GetController().GetLastCommittedEntry())
->GetFrameEntry(new_root->child_at(0)));
GURL grandchild_url(embedded_test_server()->GetURL(
"bar.com", "/navigation_controller/simple_page_1.html"));
{
LoadCommittedCapturer capturer(new_shell->web_contents());
EXPECT_TRUE(ExecJs(new_root->child_at(0),
JsReplace(kAddFrameWithSrcScript, grandchild_url)));
capturer.Wait();
}
ASSERT_EQ(1U, new_root->child_at(0)->child_count());
EXPECT_EQ(grandchild_url, new_root->child_at(0)->child_at(0)->current_url());
EXPECT_EQ(
grandchild_url,
static_cast<NavigationEntryImpl*>(
new_shell->web_contents()->GetController().GetLastCommittedEntry())
->GetFrameEntry(new_root->child_at(0)->child_at(0))
->url());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
OriginChangeAfterDocumentWrite) {
GURL url1 = embedded_test_server()->GetURL("/title1.html");
GURL url2 = embedded_test_server()->GetURL("/title2.html");
EXPECT_TRUE(NavigateToURL(shell(), url1));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ShellAddedObserver new_shell_observer;
EXPECT_TRUE(ExecJs(root, "var w = window.open('" + url2.spec() + "');"));
Shell* new_shell = new_shell_observer.GetShell();
ASSERT_NE(new_shell->web_contents(), shell()->web_contents());
EXPECT_TRUE(WaitForLoadStop(new_shell->web_contents()));
FrameTreeNode* new_root =
static_cast<WebContentsImpl*>(new_shell->web_contents())
->GetPrimaryFrameTree()
.root();
GURL blank_url(url::kAboutBlankURL);
{
TestNavigationObserver nav_observer(new_shell->web_contents());
EXPECT_TRUE(ExecJs(new_shell, "location.href = 'about:blank';"));
nav_observer.Wait();
EXPECT_EQ(2, new_shell->web_contents()->GetController().GetEntryCount());
EXPECT_EQ(blank_url, new_root->current_url());
EXPECT_EQ(blank_url,
new_root->current_frame_host()->last_document_url_in_renderer());
}
{
LoadCommittedCapturer capturer(new_shell->web_contents());
std::string html = "<iframe src='" + url2.spec() + "'></iframe>";
std::string script = JsReplace(
"w.document.write($1);"
"w.document.close();",
html);
EXPECT_TRUE(ExecJs(root->current_frame_host(), script));
capturer.Wait();
}
ASSERT_EQ(1U, new_root->child_count());
EXPECT_EQ(blank_url, new_root->current_url());
EXPECT_EQ(url1,
new_root->current_frame_host()->last_document_url_in_renderer());
EXPECT_EQ(url2, new_root->child_at(0)->current_url());
GURL url3 = embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html");
{
LoadCommittedCapturer capturer(new_root->child_at(0));
std::string script = "location.href = '" + url3.spec() + "';";
EXPECT_TRUE(ExecJs(new_root->child_at(0), script));
capturer.Wait();
}
EXPECT_EQ(blank_url, new_root->current_url());
EXPECT_EQ(url1,
new_root->current_frame_host()->last_document_url_in_renderer());
EXPECT_EQ(url3, new_root->child_at(0)->current_url());
EXPECT_EQ(3, new_shell->web_contents()->GetController().GetEntryCount());
{
LoadCommittedCapturer capturer(new_root);
std::string script = "history.replaceState({}, 'foo', 'foo');";
EXPECT_TRUE(ExecJs(new_root, script));
capturer.Wait();
}
GURL replace_state_url(embedded_test_server()->GetURL("/foo"));
EXPECT_EQ(replace_state_url, new_root->current_url());
EXPECT_EQ(replace_state_url,
new_root->current_frame_host()->last_document_url_in_renderer());
EXPECT_EQ(url3, new_root->child_at(0)->current_url());
{
TestNavigationObserver observer(new_shell->web_contents(), 1);
new_shell->web_contents()->GetController().GoBack();
observer.Wait();
EXPECT_EQ(replace_state_url, new_shell->web_contents()
->GetController()
.GetLastCommittedEntry()
->GetURL());
EXPECT_EQ(replace_state_url, new_root->current_url());
EXPECT_EQ(replace_state_url,
new_root->current_frame_host()->last_document_url_in_renderer());
EXPECT_EQ(url2, new_root->child_at(0)->current_url());
}
EXPECT_TRUE(new_root->current_frame_host()->IsRenderFrameLive());
{
TestNavigationObserver observer(new_shell->web_contents(), 1);
new_shell->web_contents()->GetController().GoForward();
observer.Wait();
EXPECT_EQ(replace_state_url, new_shell->web_contents()
->GetController()
.GetLastCommittedEntry()
->GetURL());
EXPECT_EQ(replace_state_url, new_root->current_url());
EXPECT_EQ(url3, new_root->child_at(0)->current_url());
}
EXPECT_TRUE(new_root->current_frame_host()->IsRenderFrameLive());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
DocumentOpenFromSibling) {
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe_simple.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(1U, root->child_count());
GURL first_frame_url = root->child_at(0)->current_url();
GURL second_frame_url(embedded_test_server()->GetURL("/title2.html"));
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(
ExecJs(root, JsReplace(kAddFrameWithSrcScript, second_frame_url)));
capturer.Wait();
}
EXPECT_EQ(2U, root->child_count());
EXPECT_TRUE(ExecJs(
root->child_at(1),
"parent.document.getElementById(\"frame\").contentDocument.open();"));
EXPECT_TRUE(ExecJs(root->child_at(1), "true"));
EXPECT_TRUE(ExecJs(root->child_at(0), "true"));
RenderFrameHostImpl* child0 = root->child_at(0)->current_frame_host();
RenderFrameHostImpl* child1 = root->child_at(1)->current_frame_host();
EXPECT_EQ(first_frame_url, child0->GetLastCommittedURL());
EXPECT_EQ(second_frame_url, child0->last_document_url_in_renderer());
EXPECT_EQ(second_frame_url, child1->GetLastCommittedURL());
EXPECT_EQ(second_frame_url, child1->last_document_url_in_renderer());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
DocumentOpenFromAboutBlank) {
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe_simple.html"));
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
{
LoadCommittedCapturer capturer(contents());
EXPECT_EQ("done", EvalJs(root->current_frame_host(), R"(
new Promise(async resolve => {
const blank_iframe = document.createElement('iframe');
await new Promise(resolve => {
blank_iframe.onload = resolve;
document.body.appendChild(blank_iframe);
});
let script = document.createElement('script');
script.text = `
const sibling = parent.document.getElementById("frame")
sibling.contentDocument.open();
`;
blank_iframe.contentDocument.body.appendChild(script);
resolve("done");
})
)"));
capturer.Wait();
}
EXPECT_TRUE(ExecJs(root->child_at(1), "true"));
EXPECT_TRUE(ExecJs(root->child_at(0), "true"));
ASSERT_EQ(2U, root->child_count());
RenderFrameHostImpl* child0 = root->child_at(0)->current_frame_host();
RenderFrameHostImpl* child1 = root->child_at(1)->current_frame_host();
EXPECT_EQ(frame_url, child0->GetLastCommittedURL());
EXPECT_EQ(GURL(url::kAboutBlankURL), child0->last_document_url_in_renderer());
EXPECT_EQ(GURL(url::kAboutBlankURL), child1->GetLastCommittedURL());
EXPECT_EQ(GURL(url::kAboutBlankURL), child1->last_document_url_in_renderer());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
DocumentOpenFromSrcdoc) {
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe_simple.html"));
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
{
LoadCommittedCapturer capturer(contents());
std::string script =
"let origin = document.createElement('iframe');"
"origin.srcdoc = '<script>parent.document.getElementById(\"frame\")"
".contentDocument.open();</script>';"
"document.body.appendChild(origin);";
EXPECT_TRUE(ExecJs(root->current_frame_host(), script));
capturer.Wait();
}
EXPECT_TRUE(ExecJs(root->child_at(1), "true"));
EXPECT_TRUE(ExecJs(root->child_at(0), "true"));
ASSERT_EQ(2U, root->child_count());
RenderFrameHostImpl* child0 = root->child_at(0)->current_frame_host();
RenderFrameHostImpl* child1 = root->child_at(1)->current_frame_host();
EXPECT_EQ(frame_url, child0->GetLastCommittedURL());
EXPECT_EQ(GURL("about:srcdoc"), child0->last_document_url_in_renderer());
EXPECT_EQ(GURL("about:srcdoc"), child1->GetLastCommittedURL());
EXPECT_EQ(GURL("about:srcdoc"), child1->last_document_url_in_renderer());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
DocumentOpenFromBloblIframe) {
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe_simple.html"));
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
{
LoadCommittedCapturer capturer(contents());
std::string script =
"let origin = document.createElement('iframe');"
"let blob = new Blob(['<script>"
"parent.document.getElementById(\"frame\").contentDocument.open();"
"</script>'], { type: 'text/html' });"
"origin.src = URL.createObjectURL(blob);"
"document.body.appendChild(origin);";
EXPECT_TRUE(ExecJs(root->current_frame_host(), script));
capturer.Wait();
}
EXPECT_TRUE(ExecJs(root->child_at(1), "true"));
EXPECT_TRUE(ExecJs(root->child_at(0), "true"));
ASSERT_EQ(2U, root->child_count());
RenderFrameHostImpl* child0 = root->child_at(0)->current_frame_host();
RenderFrameHostImpl* child1 = root->child_at(1)->current_frame_host();
EXPECT_EQ(frame_url, child0->GetLastCommittedURL());
EXPECT_TRUE(child0->last_document_url_in_renderer().SchemeIsBlob());
EXPECT_TRUE(child1->GetLastCommittedURL().SchemeIsBlob());
EXPECT_TRUE(child1->last_document_url_in_renderer().SchemeIsBlob());
EXPECT_EQ(child0->last_document_url_in_renderer(),
child1->last_document_url_in_renderer());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, RendererURLs) {
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe_simple.html"));
GURL iframe_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(url1, root->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(url1, root->current_frame_host()->last_document_url_in_renderer());
FrameTreeNode* iframe = root->child_at(0);
EXPECT_EQ(iframe_url, iframe->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(iframe_url,
iframe->current_frame_host()->last_document_url_in_renderer());
EXPECT_TRUE(ExecJs(
root, "document.getElementById(\"frame\").contentDocument.open();"));
EXPECT_TRUE(ExecJs(root, "true"));
EXPECT_TRUE(ExecJs(iframe, "true"));
EXPECT_EQ(iframe_url, iframe->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(url1,
iframe->current_frame_host()->last_document_url_in_renderer());
GURL url_1_fragment(url1.spec() + "#foo");
{
FrameNavigateParamsCapturer capturer(iframe);
capturer.set_wait_for_load(false);
EXPECT_TRUE(
ExecJs(iframe, JsReplace("location.href = '#foo';", url_1_fragment)));
capturer.Wait();
EXPECT_TRUE(capturer.is_same_document());
}
EXPECT_EQ(url_1_fragment,
iframe->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(url_1_fragment,
iframe->current_frame_host()->last_document_url_in_renderer());
GURL url404(embedded_test_server()->GetURL("/empty404.html"));
EXPECT_FALSE(NavigateToURL(shell(), url404));
EXPECT_EQ(url404, root->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(GURL(kUnreachableWebDataURL),
root->current_frame_host()->last_document_url_in_renderer());
{
FrameNavigateParamsCapturer capturer(root);
capturer.set_wait_for_load(false);
EXPECT_TRUE(ExecJs(shell(), "history.pushState('', '')"));
capturer.Wait();
EXPECT_TRUE(capturer.is_same_document());
}
EXPECT_EQ(url404, root->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(GURL(kUnreachableWebDataURL),
root->current_frame_host()->last_document_url_in_renderer());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, ErrorPageReplacement) {
NavigationController& controller = shell()->web_contents()->GetController();
GetIOThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&net::URLRequestFailedJob::AddUrlHandler));
GURL url1 = embedded_test_server()->GetURL("/title1.html");
EXPECT_TRUE(NavigateToURL(shell(), url1));
EXPECT_EQ(1, controller.GetEntryCount());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL error_url = embedded_test_server()->GetURL("/close-socket");
{
FrameNavigateParamsCapturer capturer(root);
NavigateFrameToURL(root, error_url);
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
EXPECT_EQ(2, controller.GetEntryCount());
}
{
FrameNavigateParamsCapturer capturer(root);
NavigateFrameToURL(root, error_url);
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
EXPECT_EQ(2, controller.GetEntryCount());
}
GURL url2 = embedded_test_server()->GetURL("/title2.html");
{
auto url_loader_interceptor = std::make_unique<URLLoaderInterceptor>(
base::BindRepeating([](URLLoaderInterceptor::RequestParams* params) {
network::URLLoaderCompletionStatus status;
status.error_code = net::ERR_NOT_IMPLEMENTED;
params->client->OnComplete(status);
return true;
}));
FrameNavigateParamsCapturer capturer(root);
NavigateFrameToURL(root, url2);
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_FALSE(capturer.did_replace_entry());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
}
{
FrameNavigateParamsCapturer capturer(root);
controller.GoBack();
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_FALSE(capturer.did_replace_entry());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
}
{
FrameNavigateParamsCapturer capturer(root);
controller.GoForward();
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_NE(PAGE_TYPE_ERROR, entry->GetPageType());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
}
EXPECT_TRUE(NavigateToURL(shell(), url1));
EXPECT_EQ(4, controller.GetEntryCount());
{
FrameNavigateParamsCapturer capturer(root);
RendererLocationReplace(shell(), error_url);
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
EXPECT_EQ(4, controller.GetEntryCount());
}
GURL web_ui_page(std::string(kChromeUIScheme) + "://" +
std::string(kChromeUIGpuHost));
EXPECT_TRUE(NavigateToURL(shell(), web_ui_page));
EXPECT_EQ(5, controller.GetEntryCount());
{
FrameNavigateParamsCapturer capturer(root);
RendererLocationReplace(shell(), error_url);
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
EXPECT_EQ(5, controller.GetEntryCount());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
ErrorPageReplacementSubframe) {
NavigationController& controller = shell()->web_contents()->GetController();
GURL main_frame_url = embedded_test_server()->GetURL(
"/navigation_controller/page_with_data_iframe.html");
EXPECT_TRUE(NavigateToURL(shell(), main_frame_url));
EXPECT_EQ(1, controller.GetEntryCount());
GURL error_url = embedded_test_server()->GetURL("/close-socket");
GetIOThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&net::URLRequestFailedJob::AddUrlHandler));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
NavigateFrameToURL(root->child_at(0), error_url);
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
EXPECT_EQ(2, controller.GetEntryCount());
}
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
NavigateFrameToURL(root->child_at(0), error_url);
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_EQ(2, controller.GetEntryCount());
}
GURL url2 = embedded_test_server()->GetURL("/title1.html");
{
auto url_loader_interceptor = std::make_unique<URLLoaderInterceptor>(
base::BindRepeating([](URLLoaderInterceptor::RequestParams* params) {
network::URLLoaderCompletionStatus status;
status.error_code = net::ERR_NOT_IMPLEMENTED;
params->client->OnComplete(status);
return true;
}));
FrameNavigateParamsCapturer capturer(root->child_at(0));
NavigateFrameToURL(root->child_at(0), url2);
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
}
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
controller.GoBack();
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
}
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
controller.GoForward();
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
}
{
auto url_loader_interceptor = std::make_unique<URLLoaderInterceptor>(
base::BindRepeating([](URLLoaderInterceptor::RequestParams* params) {
network::URLLoaderCompletionStatus status;
status.error_code = net::ERR_NOT_IMPLEMENTED;
params->client->OnComplete(status);
return true;
}));
FrameNavigateParamsCapturer capturer(root->child_at(0));
NavigateFrameToURL(root->child_at(0), url2);
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
NavigationTypeClassification_NewEntry) {
EXPECT_TRUE(NavigateToURL(shell(), GURL(url::kAboutBlankURL)));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
{
FrameNavigateParamsCapturer capturer(root);
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_links.html"));
NavigateFrameToURL(root, frame_url);
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_LINK));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_FALSE(capturer.is_same_document());
}
NavigationEntryImpl* previous_entry = controller.GetLastCommittedEntry();
scoped_refptr<FrameNavigationEntry> previous_root_entry =
previous_entry->root_node()->frame_entry.get();
{
FrameNavigateParamsCapturer capturer(root);
std::string script = "document.getElementById('fraglink').click()";
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_LINK));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_NE(
previous_root_entry,
controller.GetLastCommittedEntry()->root_node()->frame_entry.get());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
previous_entry = controller.GetLastCommittedEntry();
previous_root_entry = previous_entry->root_node()->frame_entry.get();
}
{
FrameNavigateParamsCapturer capturer(root);
std::string script = "document.getElementById('thelink').click()";
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_LINK));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_FALSE(capturer.is_same_document());
EXPECT_NE(
previous_root_entry,
controller.GetLastCommittedEntry()->root_node()->frame_entry.get());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
previous_entry = controller.GetLastCommittedEntry();
previous_root_entry = previous_entry->root_node()->frame_entry.get();
}
{
FrameNavigateParamsCapturer capturer(root);
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
std::string script = JsReplace("location.assign($1);", frame_url);
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_LINK));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_FALSE(capturer.is_same_document());
EXPECT_NE(
previous_root_entry,
controller.GetLastCommittedEntry()->root_node()->frame_entry.get());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
previous_entry = controller.GetLastCommittedEntry();
previous_root_entry = previous_entry->root_node()->frame_entry.get();
}
{
FrameNavigateParamsCapturer capturer(root);
std::string script =
"history.pushState({}, 'page 1', 'simple_page_1.html')";
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_LINK));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_NE(
previous_root_entry,
controller.GetLastCommittedEntry()->root_node()->frame_entry.get());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
previous_entry = controller.GetLastCommittedEntry();
previous_root_entry = previous_entry->root_node()->frame_entry.get();
}
{
FrameNavigateParamsCapturer capturer(root);
GURL frame_url(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_1.html"));
std::string script = JsReplace("location.replace($1);", frame_url);
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_FALSE(capturer.is_same_document());
EXPECT_NE(
previous_root_entry,
controller.GetLastCommittedEntry()->root_node()->frame_entry.get());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
NavigationTypeClassification_ExistingEntry) {
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
GURL url2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
EXPECT_TRUE(NavigateToURL(shell(), url2));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
{
FrameNavigateParamsCapturer capturer(root);
controller.GoBack();
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FORWARD_BACK |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_FALSE(capturer.is_same_document());
}
{
FrameNavigateParamsCapturer capturer(root);
controller.GoForward();
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FORWARD_BACK |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_FALSE(capturer.is_same_document());
}
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "history.back()"));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FORWARD_BACK |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_FALSE(capturer.is_same_document());
}
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "history.forward()"));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FORWARD_BACK |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_FALSE(capturer.is_same_document());
}
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "history.go(-1)"));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FORWARD_BACK |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_FALSE(capturer.is_same_document());
}
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "history.go(1)"));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FORWARD_BACK |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_FALSE(capturer.is_same_document());
}
ReplaceState(root, "foo");
EXPECT_EQ("foo", EvalJs(root, "history.state"));
NavigationEntryImpl* previous_entry = controller.GetLastCommittedEntry();
{
FrameNavigateParamsCapturer capturer(root);
controller.Reload(ReloadType::NORMAL, false);
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_RELOAD));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_FALSE(capturer.is_same_document());
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ("foo", EvalJs(root, "history.state"));
previous_entry = controller.GetLastCommittedEntry();
}
{
FrameNavigateParamsCapturer capturer(root);
shell()->web_contents()->GetPrimaryMainFrame()->Reload();
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_RELOAD));
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ("foo", EvalJs(root, "history.state"));
previous_entry = controller.GetLastCommittedEntry();
}
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "location.reload()"));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_FALSE(capturer.is_same_document());
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ("foo", EvalJs(root, "history.state"));
previous_entry = controller.GetLastCommittedEntry();
}
auto url_loader_interceptor = std::make_unique<URLLoaderInterceptor>(
base::BindRepeating([](URLLoaderInterceptor::RequestParams* params) {
network::URLLoaderCompletionStatus status;
status.error_code = net::ERR_NOT_IMPLEMENTED;
params->client->OnComplete(status);
return true;
}));
{
TestNavigationObserver reload_observer(shell()->web_contents());
FrameNavigateParamsCapturer capturer(root);
shell()->Reload();
capturer.Wait();
EXPECT_FALSE(reload_observer.last_navigation_succeeded());
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_RELOAD));
EXPECT_FALSE(capturer.did_replace_entry());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(previous_entry, entry);
EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
previous_entry = entry;
}
{
TestNavigationObserver reload_observer(shell()->web_contents());
FrameNavigateParamsCapturer capturer(root);
shell()->Reload();
capturer.Wait();
EXPECT_FALSE(reload_observer.last_navigation_succeeded());
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_RELOAD));
EXPECT_FALSE(capturer.did_replace_entry());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(previous_entry, entry);
EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
previous_entry = entry;
}
url_loader_interceptor.reset();
{
TestNavigationObserver reload_observer(shell()->web_contents());
FrameNavigateParamsCapturer capturer(root);
shell()->Reload();
capturer.Wait();
EXPECT_TRUE(reload_observer.last_navigation_succeeded());
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_RELOAD));
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(nullptr, EvalJs(root, "history.state"));
previous_entry = controller.GetLastCommittedEntry();
}
{
FrameNavigateParamsCapturer capturer(root);
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
std::string script = JsReplace("location.replace($1);", frame_url);
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_FALSE(capturer.is_same_document());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
previous_entry = controller.GetLastCommittedEntry();
}
scoped_refptr<FrameNavigationEntry> previous_root_entry =
previous_entry->root_node()->frame_entry.get();
{
FrameNavigateParamsCapturer capturer(root);
std::string script = "location.replace('#foo')";
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ(
previous_root_entry,
controller.GetLastCommittedEntry()->root_node()->frame_entry.get());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
previous_entry = controller.GetLastCommittedEntry();
previous_root_entry = previous_entry->root_node()->frame_entry.get();
}
{
FrameNavigateParamsCapturer capturer(root);
std::string script =
"history.replaceState({}, 'page 2', 'simple_page_2.html')";
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ(
previous_root_entry,
controller.GetLastCommittedEntry()->root_node()->frame_entry.get());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
previous_entry = controller.GetLastCommittedEntry();
}
GURL url_links(embedded_test_server()->GetURL(
"/navigation_controller/page_with_links.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_links));
std::string script = "document.getElementById('fraglink').click()";
EXPECT_TRUE(ExecJs(root, script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
{
FrameNavigateParamsCapturer capturer(root);
shell()->web_contents()->GetController().GoBack();
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FORWARD_BACK |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_TRUE(capturer.is_same_document());
}
{
FrameNavigateParamsCapturer capturer(root);
controller.GoForward();
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
ui::PAGE_TRANSITION_FORWARD_BACK)));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_TRUE(capturer.is_same_document());
}
EXPECT_TRUE(NavigateToURL(shell(), url1));
script = "history.pushState({}, 'page 2', 'simple_page_2.html')";
EXPECT_TRUE(ExecJs(root, script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
{
FrameNavigateParamsCapturer capturer(root);
controller.GoBack();
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FORWARD_BACK |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_TRUE(capturer.is_same_document());
}
{
FrameNavigateParamsCapturer capturer(root);
controller.GoForward();
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
ui::PAGE_TRANSITION_FORWARD_BACK)));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_TRUE(capturer.is_same_document());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
NavigationTypeClassification_ExistingEntrySameURL) {
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(1, controller.GetEntryCount());
ReplaceState(root, "foo");
EXPECT_EQ("foo", EvalJs(root, "history.state"));
NavigationEntryImpl* previous_entry = controller.GetLastCommittedEntry();
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(NavigateToURL(shell(), url1));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_FALSE(shell()->web_contents()->GetController().GetPendingEntry());
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ("foo", EvalJs(root, "history.state"));
previous_entry = controller.GetLastCommittedEntry();
}
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(NavigateToURLFromRenderer(root, url1));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ("foo", EvalJs(root, "history.state"));
previous_entry = controller.GetLastCommittedEntry();
}
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, JsReplace("location.replace($1);", url1)));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ("foo", EvalJs(root, "history.state"));
previous_entry = controller.GetLastCommittedEntry();
}
auto url_loader_interceptor = std::make_unique<URLLoaderInterceptor>(
base::BindRepeating([](URLLoaderInterceptor::RequestParams* params) {
network::URLLoaderCompletionStatus status;
status.error_code = net::ERR_NOT_IMPLEMENTED;
params->client->OnComplete(status);
return true;
}));
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_FALSE(NavigateToURLFromRenderer(shell(), url1));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(1, controller.GetEntryCount());
previous_entry = controller.GetLastCommittedEntry();
}
{
FrameNavigateParamsCapturer capturer(root);
shell()->Reload();
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(1, controller.GetEntryCount());
previous_entry = controller.GetLastCommittedEntry();
}
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_FALSE(NavigateToURL(shell(), url1));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(1, controller.GetEntryCount());
previous_entry = controller.GetLastCommittedEntry();
}
url_loader_interceptor.reset();
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(NavigateToURL(shell(), url1));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(nullptr, EvalJs(root, "history.state"));
previous_entry = controller.GetLastCommittedEntry();
}
ReplaceState(root, "foo");
EXPECT_EQ("foo", EvalJs(root, "history.state"));
previous_entry = controller.GetLastCommittedEntry();
{
FrameNavigateParamsCapturer capturer(root);
NavigationController::LoadURLParams params(url1);
params.transition_type = ui::PageTransitionFromInt(
ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
params.should_replace_current_entry = true;
contents()->GetController().LoadURLWithParams(params);
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ("foo", EvalJs(root, "history.state"));
previous_entry = controller.GetLastCommittedEntry();
}
{
url_loader_interceptor = std::make_unique<URLLoaderInterceptor>(
base::BindRepeating([](URLLoaderInterceptor::RequestParams* params) {
network::URLLoaderCompletionStatus status;
status.error_code = net::ERR_NOT_IMPLEMENTED;
params->client->OnComplete(status);
return true;
}));
FrameNavigateParamsCapturer capturer(root);
NavigationController::LoadURLParams params(url1);
params.transition_type = ui::PageTransitionFromInt(
ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
params.should_replace_current_entry = true;
contents()->GetController().LoadURLWithParams(params);
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(2, controller.GetEntryCount());
url_loader_interceptor.reset();
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
NavigationTypeClassification_ExistingEntrySameURL_WebUI) {
GURL web_ui_url(std::string(kChromeUIScheme) + "://" +
std::string(kChromeUIGpuHost));
EXPECT_TRUE(NavigateToURL(shell(), web_ui_url));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* previous_entry = controller.GetLastCommittedEntry();
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(NavigateToURL(shell(), web_ui_url));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_FALSE(shell()->web_contents()->GetController().GetPendingEntry());
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(1, controller.GetEntryCount());
previous_entry = controller.GetLastCommittedEntry();
}
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(contents(), JsReplace("location.href = $1", web_ui_url),
EXECUTE_SCRIPT_DEFAULT_OPTIONS, 1 ));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(1, controller.GetEntryCount());
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
NavigationTypeClassification_ExistingEntrySameURLRedirect) {
GURL url1(embedded_test_server()->GetURL("/title1.html"));
GURL url2(embedded_test_server()->GetURL("/title2.html"));
GURL redirect_to_url2(
embedded_test_server()->GetURL("/server-redirect?" + url2.spec()));
EXPECT_TRUE(NavigateToURL(shell(), url1));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
EXPECT_EQ(1, controller.GetEntryCount());
FrameTreeNode* root =
static_cast<WebContentsImpl*>(contents())->GetPrimaryFrameTree().root();
ReplaceState(root, "", redirect_to_url2);
NavigationEntryImpl* previous_entry = controller.GetLastCommittedEntry();
EXPECT_EQ(redirect_to_url2, previous_entry->GetURL());
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(NavigateToURL(shell(), redirect_to_url2, url2));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL());
EXPECT_EQ(1, controller.GetEntryCount());
}
ReplaceState(root, "", redirect_to_url2);
previous_entry = controller.GetLastCommittedEntry();
EXPECT_EQ(redirect_to_url2, previous_entry->GetURL());
EXPECT_EQ(1, controller.GetEntryCount());
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(NavigateToURLFromRenderer(root, redirect_to_url2, url2));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL());
EXPECT_EQ(1, controller.GetEntryCount());
}
ReplaceState(root, "", redirect_to_url2);
previous_entry = controller.GetLastCommittedEntry();
EXPECT_EQ(redirect_to_url2, previous_entry->GetURL());
EXPECT_EQ(1, controller.GetEntryCount());
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(contents(),
JsReplace(R"(var form = document.createElement('form');
form.method = 'POST';
form.action = $1;
document.body.appendChild(form);
form.submit();)",
redirect_to_url2)));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_FALSE(controller.GetLastCommittedEntry()->GetHasPostData());
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
NavigationTypeClassification_ExistingEntrySameURLWithFragment) {
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html#foo"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ReplaceState(root, "foo");
EXPECT_EQ("foo", EvalJs(root, "history.state"));
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* previous_entry = controller.GetLastCommittedEntry();
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(NavigateToURL(shell(), url1));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_FALSE(capturer.is_same_document());
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ("foo", EvalJs(root, "history.state"));
previous_entry = controller.GetLastCommittedEntry();
}
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(NavigateToURLFromRenderer(root, url1));
capturer.Wait();
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ("foo", EvalJs(root, "history.state"));
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, ReloadWithUrlAnchor) {
GURL url(embedded_test_server()->GetURL(
"/navigation_controller/reload-with-url-anchor.html#center-element"));
EXPECT_TRUE(NavigateToURL(shell(), url));
double window_scroll_y = EvalJs(shell(), "window.scrollY").ExtractDouble();
bool fractional_scroll_offsets_enabled = IsFractionalScrollOffsetsEnabled();
double expected_window_scroll_y = 2000;
if (!fractional_scroll_offsets_enabled) {
float device_scale_factor = shell()
->web_contents()
->GetRenderWidgetHostView()
->GetDeviceScaleFactor();
expected_window_scroll_y =
floor(device_scale_factor * expected_window_scroll_y) /
device_scale_factor;
}
EXPECT_FLOAT_EQ(expected_window_scroll_y, window_scroll_y);
ReloadBlockUntilNavigationsComplete(shell(), 1);
window_scroll_y = EvalJs(shell(), "window.scrollY").ExtractDouble();
EXPECT_FLOAT_EQ(expected_window_scroll_y, window_scroll_y);
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
ReloadWithUrlAnchorAndScroll) {
GURL url(embedded_test_server()->GetURL(
"/navigation_controller/reload-with-url-anchor.html#center-element"));
EXPECT_TRUE(NavigateToURL(shell(), url));
std::string script_scroll_down = "window.scroll(0, 2100)";
EXPECT_TRUE(ExecJs(shell(), script_scroll_down));
double window_scroll_y = EvalJs(shell(), "window.scrollY").ExtractDouble();
bool fractional_scroll_offsets_enabled = IsFractionalScrollOffsetsEnabled();
double expected_window_scroll_y = 2100;
if (!fractional_scroll_offsets_enabled) {
float device_scale_factor = shell()
->web_contents()
->GetRenderWidgetHostView()
->GetDeviceScaleFactor();
expected_window_scroll_y =
floor(device_scale_factor * expected_window_scroll_y) /
device_scale_factor;
}
EXPECT_FLOAT_EQ(expected_window_scroll_y, window_scroll_y);
ReloadBlockUntilNavigationsComplete(shell(), 1);
window_scroll_y = EvalJs(shell(), "window.scrollY").ExtractDouble();
EXPECT_FLOAT_EQ(expected_window_scroll_y, window_scroll_y);
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
NavigationTypeClassification_EmptyGURL) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(1, controller.GetEntryCount());
{
FrameNavigateParamsCapturer capturer(root);
NavigateFrameToURL(root, GURL());
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_LINK));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_EQ(2, controller.GetEntryCount());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
RendererInitiatedNavigationToEmptyGURLFails) {
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_FALSE(NavigateToURLFromRenderer(root, GURL()));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
NavigationTypeClassification_NewAndAutoSubframe) {
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(1U, root->child_count());
ASSERT_NE(nullptr, root->child_at(0));
{
LoadCommittedCapturer capturer(root->child_at(0));
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
}
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
shell()->web_contents()->GetController().GoBack();
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
}
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
shell()->web_contents()->GetController().GoForward();
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
}
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_links.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
}
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
std::string script = "document.getElementById('fraglink').click()";
EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
}
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
std::string script = JsReplace("location.assign($1);", frame_url);
EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
}
{
LoadCommittedCapturer capturer(root->child_at(0));
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
std::string script = JsReplace("location.replace($1);", frame_url);
EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
std::string script =
"history.pushState({}, 'page 1', 'simple_page_1.html')";
EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
}
{
LoadCommittedCapturer capturer(root->child_at(0));
std::string script =
"history.replaceState({}, 'page 2', 'simple_page_2.html')";
EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
{
LoadCommittedCapturer capturer(root->child_at(0));
EXPECT_TRUE(ExecJs(root->child_at(0), "location.reload()"));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
{
LoadCommittedCapturer capturer(shell()->web_contents());
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(ExecJs(root, JsReplace(kAddFrameWithSrcScript, frame_url)));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
}
class LoadCommittedDetailsObserver : public WebContentsObserver {
public:
explicit LoadCommittedDetailsObserver(WebContents* web_contents)
: WebContentsObserver(web_contents) {}
void Wait() { loop_.Run(); }
const LoadCommittedDetails& load_details() { return load_details_; }
private:
void NavigationEntryCommitted(
const LoadCommittedDetails& load_details) override {
load_details_ = load_details;
loop_.Quit();
}
LoadCommittedDetails load_details_;
base::RunLoop loop_;
};
class InitialEmptyDocNavigationControllerBrowserTest
: public NavigationControllerBrowserTestBase,
public testing::WithParamInterface<
std::tuple<std::string, bool /* renderer_initiated */>> {
public:
InitialEmptyDocNavigationControllerBrowserTest() {
InitAndEnableRenderDocumentFeature(&feature_list_for_render_document_,
std::get<0>(GetParam()));
}
static std::string DescribeParams(
const testing::TestParamInfo<ParamType>& info) {
auto [render_document_level, renderer_initiated] = info.param;
return base::StringPrintf(
"%s_%s",
GetRenderDocumentLevelNameForTestParams(render_document_level).c_str(),
renderer_initiated ? "RendererInitiated" : "BrowserInitiated");
}
protected:
bool renderer_initiated() { return std::get<1>(GetParam()); }
void NavigateSubframeAndCheckNavigationType(WebContentsImpl* web_contents,
FrameTreeNode* node,
std::string frame_id,
const GURL& url,
NavigationType expected_type) {
DCHECK(!node->IsMainFrame());
FrameNavigateParamsCapturer capturer(node);
if (renderer_initiated()) {
EXPECT_TRUE(NavigateIframeToURL(web_contents, frame_id, url));
} else {
EXPECT_TRUE(NavigateFrameToURL(node, url));
}
capturer.Wait();
EXPECT_EQ(expected_type, capturer.navigation_type());
if (expected_type == NAVIGATION_TYPE_AUTO_SUBFRAME) {
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
EXPECT_TRUE(capturer.did_replace_entry());
} else {
EXPECT_EQ(expected_type, NAVIGATION_TYPE_NEW_SUBFRAME);
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
EXPECT_FALSE(capturer.did_replace_entry());
}
}
void NavigateWindowAndCheck(WebContentsImpl* web_contents,
const GURL& url,
bool wait_for_previous_navigations = true,
bool expect_same_document = false,
NavigationType expected_navigation_type =
NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY,
bool expect_replace = true) {
FrameTreeNode* root = web_contents->GetPrimaryFrameTree().root();
LoadCommittedDetailsObserver load_details_observer(web_contents);
FrameNavigateParamsCapturer capturer(root);
if (renderer_initiated()) {
EXPECT_TRUE(NavigateToURLFromRenderer(web_contents, url));
} else {
if (!wait_for_previous_navigations) {
NavigationController::LoadURLParams params(url);
params.transition_type = ui::PageTransitionFromInt(
ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
web_contents->GetController().LoadURLWithParams(params);
} else {
EXPECT_TRUE(NavigateToURL(web_contents, url));
}
}
capturer.Wait();
load_details_observer.Wait();
EXPECT_EQ(expected_navigation_type, capturer.navigation_type());
EXPECT_EQ(expect_replace, capturer.did_replace_entry());
EXPECT_EQ(expect_same_document, capturer.is_same_document());
EXPECT_EQ(expect_same_document,
load_details_observer.load_details().is_same_document);
}
private:
base::test::ScopedFeatureList feature_list_for_render_document_;
};
IN_PROC_BROWSER_TEST_P(InitialEmptyDocNavigationControllerBrowserTest,
NavigateNewSubframe) {
GURL url_1(embedded_test_server()->GetURL("/title1.html"));
GURL url_2(embedded_test_server()->GetURL("/title2.html"));
GURL no_commit_url(embedded_test_server()->GetURL("/page204.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_1));
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
EXPECT_EQ(1, controller.GetEntryCount());
int subframe_index = 0;
int expected_entry_count = 1;
{
SCOPED_TRACE(testing::Message() << " Testing case 1.");
CreateSubframe(contents(), "child1", GURL(),
false );
FrameTreeNode* new_subframe = root->child_at(subframe_index);
EXPECT_TRUE(new_subframe->is_on_initial_empty_document());
NavigateSubframeAndCheckNavigationType(contents(), new_subframe, "child1",
url_2,
NAVIGATION_TYPE_AUTO_SUBFRAME);
EXPECT_EQ(expected_entry_count, controller.GetEntryCount());
}
{
SCOPED_TRACE(testing::Message() << " Testing case 2.");
CreateSubframe(contents(), "child2", GURL("about:blank"),
true );
subframe_index++;
EXPECT_EQ(expected_entry_count, controller.GetEntryCount());
FrameTreeNode* new_subframe = root->child_at(subframe_index);
EXPECT_TRUE(new_subframe->is_on_initial_empty_document());
NavigateSubframeAndCheckNavigationType(contents(), new_subframe, "child2",
GURL("about:blank#foo"),
NAVIGATION_TYPE_AUTO_SUBFRAME);
EXPECT_EQ(expected_entry_count, controller.GetEntryCount());
EXPECT_TRUE(new_subframe->is_on_initial_empty_document());
NavigateSubframeAndCheckNavigationType(contents(), new_subframe, "child2",
url_2,
NAVIGATION_TYPE_AUTO_SUBFRAME);
EXPECT_EQ(expected_entry_count, controller.GetEntryCount());
EXPECT_FALSE(new_subframe->is_on_initial_empty_document());
}
{
SCOPED_TRACE(testing::Message() << " Testing case 3.");
CreateSubframe(contents(), "child3", GURL("data:text/html,foo"),
true );
subframe_index++;
EXPECT_EQ(expected_entry_count, controller.GetEntryCount());
FrameTreeNode* new_subframe = root->child_at(subframe_index);
EXPECT_FALSE(new_subframe->is_on_initial_empty_document());
NavigateSubframeAndCheckNavigationType(contents(), new_subframe, "child3",
url_2, NAVIGATION_TYPE_NEW_SUBFRAME);
expected_entry_count++;
EXPECT_EQ(expected_entry_count, controller.GetEntryCount());
}
if (renderer_initiated()) {
SCOPED_TRACE(testing::Message() << " Testing case 4.");
CreateSubframe(contents(), "child4", no_commit_url,
false );
subframe_index++;
EXPECT_EQ(expected_entry_count, controller.GetEntryCount());
FrameTreeNode* new_subframe = root->child_at(subframe_index);
EXPECT_TRUE(new_subframe->is_on_initial_empty_document());
NavigateSubframeAndCheckNavigationType(contents(), new_subframe, "child4",
url_2,
NAVIGATION_TYPE_AUTO_SUBFRAME);
EXPECT_EQ(expected_entry_count, controller.GetEntryCount());
EXPECT_FALSE(new_subframe->is_on_initial_empty_document());
}
{
SCOPED_TRACE(testing::Message() << " Testing case 5.");
CreateSubframe(contents(), "child5", GURL(),
false );
subframe_index++;
EXPECT_EQ(expected_entry_count, controller.GetEntryCount());
FrameTreeNode* new_subframe = root->child_at(subframe_index);
EXPECT_EQ(GURL("about:blank"), new_subframe->current_url());
EXPECT_TRUE(new_subframe->is_on_initial_empty_document());
EXPECT_TRUE(ExecJs(shell(), R"(
var iframeDoc = document.getElementById("child5").contentDocument;
iframeDoc.open();
iframeDoc.write("foo");
iframeDoc.close();
)"));
EXPECT_TRUE(ExecJs(new_subframe, "true"));
EXPECT_EQ(GURL("about:blank"),
new_subframe->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(
url_1,
new_subframe->current_frame_host()->last_document_url_in_renderer());
EXPECT_FALSE(new_subframe->is_on_initial_empty_document());
NavigateSubframeAndCheckNavigationType(contents(), new_subframe, "child5",
url_2, NAVIGATION_TYPE_NEW_SUBFRAME);
expected_entry_count++;
EXPECT_EQ(expected_entry_count, controller.GetEntryCount());
EXPECT_FALSE(new_subframe->is_on_initial_empty_document());
}
{
SCOPED_TRACE(testing::Message() << " Testing case 6.");
RenderFrameHost* child6 =
CreateSubframe(contents(), "child6", GURL("javascript:'foo'"),
false );
subframe_index++;
EXPECT_EQ(expected_entry_count, controller.GetEntryCount());
FrameTreeNode* new_subframe = root->child_at(subframe_index);
EXPECT_TRUE(new_subframe->is_on_initial_empty_document());
base::RunLoop run_loop;
static_cast<RenderFrameHostImpl*>(child6)
->set_did_stop_loading_callback_for_testing(run_loop.QuitClosure());
run_loop.Run();
NavigateSubframeAndCheckNavigationType(contents(), new_subframe, "child6",
url_2,
NAVIGATION_TYPE_AUTO_SUBFRAME);
EXPECT_EQ(expected_entry_count, controller.GetEntryCount());
EXPECT_FALSE(new_subframe->is_on_initial_empty_document());
}
{
SCOPED_TRACE(testing::Message() << " Testing case 7.");
CreateSubframe(contents(), "child7", GURL("about:blank"),
true );
subframe_index++;
EXPECT_EQ(expected_entry_count, controller.GetEntryCount());
FrameTreeNode* new_subframe = root->child_at(subframe_index);
EXPECT_TRUE(new_subframe->is_on_initial_empty_document());
NavigateSubframeAndCheckNavigationType(contents(), new_subframe, "child7",
GURL("about:blank?foo"),
NAVIGATION_TYPE_AUTO_SUBFRAME);
EXPECT_EQ(expected_entry_count, controller.GetEntryCount());
EXPECT_FALSE(new_subframe->is_on_initial_empty_document());
NavigateSubframeAndCheckNavigationType(contents(), new_subframe, "child7",
url_2, NAVIGATION_TYPE_NEW_SUBFRAME);
expected_entry_count++;
EXPECT_EQ(expected_entry_count, controller.GetEntryCount());
EXPECT_FALSE(new_subframe->is_on_initial_empty_document());
}
}
IN_PROC_BROWSER_TEST_P(InitialEmptyDocNavigationControllerBrowserTest,
NavigateNewWindow) {
GURL main_window_url(embedded_test_server()->GetURL("/title1.html"));
GURL url_2(embedded_test_server()->GetURL("/title2.html"));
GURL hung_url(embedded_test_server()->GetURL("/hung"));
EXPECT_TRUE(NavigateToURL(shell(), main_window_url));
EXPECT_TRUE(ExecJs(contents(), "var last_opened_window = null;"));
{
SCOPED_TRACE(testing::Message() << " Testing case 1.");
Shell* new_shell = OpenBlankWindow(contents());
WebContentsImpl* new_contents =
static_cast<WebContentsImpl*>(new_shell->web_contents());
NavigationControllerImpl& controller = new_contents->GetController();
EXPECT_TRUE(!controller.GetLastCommittedEntry() ||
controller.GetLastCommittedEntry()->IsInitialEntry());
NavigateWindowAndCheck(new_contents, url_2);
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_FALSE(controller.GetLastCommittedEntry()->IsInitialEntry());
}
{
SCOPED_TRACE(testing::Message() << " Testing case 2.");
Shell* new_shell = OpenBlankWindow(contents());
WebContentsImpl* new_contents =
static_cast<WebContentsImpl*>(new_shell->web_contents());
NavigationControllerImpl& controller = new_contents->GetController();
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntry* last_entry = controller.GetLastCommittedEntry();
FrameTreeNode* new_root = new_contents->GetPrimaryFrameTree().root();
EXPECT_TRUE(new_root->is_on_initial_empty_document());
EXPECT_TRUE(last_entry->IsInitialEntry());
NavigateWindowAndCheck(new_contents, GURL("about:blank"),
true ,
false ,
NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY,
true );
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_NE(last_entry, controller.GetLastCommittedEntry());
last_entry = controller.GetLastCommittedEntry();
EXPECT_FALSE(new_root->is_on_initial_empty_document());
EXPECT_FALSE(last_entry->IsInitialEntry());
NavigateWindowAndCheck(new_contents, GURL("about:blank#foo"),
true ,
true ,
NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY,
false );
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_NE(last_entry, controller.GetLastCommittedEntry());
EXPECT_FALSE(new_root->is_on_initial_empty_document());
}
{
SCOPED_TRACE(testing::Message() << " Testing case 3.");
Shell* new_shell = OpenBlankWindow(contents());
WebContentsImpl* new_contents =
static_cast<WebContentsImpl*>(new_shell->web_contents());
NavigationControllerImpl& controller = new_contents->GetController();
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntry* last_entry = controller.GetLastCommittedEntry();
FrameTreeNode* new_root = new_contents->GetPrimaryFrameTree().root();
EXPECT_TRUE(new_root->is_on_initial_empty_document());
EXPECT_TRUE(last_entry->IsInitialEntry());
NavigateWindowAndCheck(new_contents, GURL("about:blank#foo"),
true ,
true ,
NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY);
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(last_entry, controller.GetLastCommittedEntry());
EXPECT_TRUE(new_root->is_on_initial_empty_document());
EXPECT_TRUE(last_entry->IsInitialEntry());
}
{
SCOPED_TRACE(testing::Message() << " Testing case 4.");
Shell* new_shell = OpenWindow(contents(), GURL("about:blank"));
WebContentsImpl* new_contents =
static_cast<WebContentsImpl*>(new_shell->web_contents());
NavigationControllerImpl& controller = new_contents->GetController();
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* last_entry = controller.GetLastCommittedEntry();
FrameTreeNode* new_root = new_contents->GetPrimaryFrameTree().root();
EXPECT_TRUE(new_root->is_on_initial_empty_document());
EXPECT_TRUE(last_entry->IsInitialEntry());
NavigateWindowAndCheck(new_contents, GURL("about:blank#foo"),
true ,
true ,
NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
true );
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(last_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(last_entry->GetMainFrameDocumentSequenceNumber(),
controller.GetLastCommittedEntry()
->GetMainFrameDocumentSequenceNumber());
last_entry = controller.GetLastCommittedEntry();
EXPECT_TRUE(new_root->is_on_initial_empty_document());
EXPECT_TRUE(last_entry->IsInitialEntry());
NavigateWindowAndCheck(
new_contents, url_2, true ,
false , NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY,
true );
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_NE(last_entry, controller.GetLastCommittedEntry());
last_entry = controller.GetLastCommittedEntry();
EXPECT_FALSE(new_root->is_on_initial_empty_document());
EXPECT_FALSE(last_entry->IsInitialEntry());
}
{
SCOPED_TRACE(testing::Message() << " Testing case 5.");
Shell* new_shell = OpenWindow(contents(), hung_url);
WebContentsImpl* new_contents =
static_cast<WebContentsImpl*>(new_shell->web_contents());
NavigationControllerImpl& controller = new_contents->GetController();
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* last_entry = controller.GetLastCommittedEntry();
FrameTreeNode* new_root = new_contents->GetPrimaryFrameTree().root();
EXPECT_TRUE(new_root->is_on_initial_empty_document());
EXPECT_TRUE(last_entry->IsInitialEntry());
NavigateWindowAndCheck(new_contents, url_2,
false );
EXPECT_EQ(1, controller.GetEntryCount());
last_entry = controller.GetLastCommittedEntry();
EXPECT_FALSE(new_root->is_on_initial_empty_document());
EXPECT_FALSE(last_entry->IsInitialEntry());
}
{
SCOPED_TRACE(testing::Message() << " Testing case 6.");
Shell* new_shell = OpenBlankWindow(contents());
WebContentsImpl* new_contents =
static_cast<WebContentsImpl*>(new_shell->web_contents());
NavigationControllerImpl& controller = new_contents->GetController();
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* last_entry = controller.GetLastCommittedEntry();
FrameTreeNode* new_root = new_contents->GetPrimaryFrameTree().root();
EXPECT_TRUE(new_root->is_on_initial_empty_document());
EXPECT_TRUE(last_entry->IsInitialEntry());
TestNavigationObserver nav_observer(new_contents);
EXPECT_TRUE(ExecJs(contents(), R"(
last_opened_window.document.open();
last_opened_window.document.write("foo");
last_opened_window.document.close();
)"));
EXPECT_TRUE(ExecJs(new_contents, "true"));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(GURL("about:blank"),
new_contents->GetPrimaryMainFrame()->GetLastCommittedURL());
EXPECT_EQ(
main_window_url,
new_contents->GetPrimaryMainFrame()->last_document_url_in_renderer());
EXPECT_FALSE(new_root->is_on_initial_empty_document());
EXPECT_TRUE(last_entry->IsInitialEntry());
NavigateWindowAndCheck(
new_contents, url_2, true ,
false , NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY,
true );
EXPECT_EQ(1, controller.GetEntryCount());
last_entry = controller.GetLastCommittedEntry();
EXPECT_FALSE(last_entry->IsInitialEntry());
}
{
SCOPED_TRACE(testing::Message() << " Testing case 7.");
Shell* new_shell = OpenWindow(contents(), GURL("javascript:'foo'"));
WebContentsImpl* new_contents =
static_cast<WebContentsImpl*>(new_shell->web_contents());
NavigationControllerImpl& controller = new_contents->GetController();
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* last_entry = controller.GetLastCommittedEntry();
FrameTreeNode* new_root = new_contents->GetPrimaryFrameTree().root();
EXPECT_TRUE(new_root->is_on_initial_empty_document());
EXPECT_TRUE(last_entry->IsInitialEntry());
NavigateWindowAndCheck(new_contents, url_2);
EXPECT_EQ(1, controller.GetEntryCount());
last_entry = controller.GetLastCommittedEntry();
EXPECT_FALSE(new_root->is_on_initial_empty_document());
EXPECT_FALSE(last_entry->IsInitialEntry());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
InitialEmptyDocumentStatusAfterCrash) {
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
EXPECT_TRUE(root->is_on_initial_empty_document());
GURL url_1(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_1));
EXPECT_FALSE(root->is_on_initial_empty_document());
CrashTab(shell()->web_contents());
GURL url_2(embedded_test_server()->GetURL("/title2.html"));
TestNavigationManager navigation_manager(shell()->web_contents(), url_2);
controller.LoadURL(url_2, Referrer(), ui::PAGE_TRANSITION_LINK,
std::string());
EXPECT_TRUE(navigation_manager.WaitForRequestStart());
EXPECT_FALSE(root->is_on_initial_empty_document());
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_FALSE(root->is_on_initial_empty_document());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
SameDocumentInInitialEmptyDocument) {
GURL main_window_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_window_url));
Shell* new_shell = OpenBlankWindow(contents());
WebContentsImpl* new_contents =
static_cast<WebContentsImpl*>(new_shell->web_contents());
NavigationControllerImpl& controller = new_contents->GetController();
FrameTreeNode* root = new_contents->GetPrimaryFrameTree().root();
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_TRUE(controller.GetLastCommittedEntry());
{
LoadCommittedDetailsObserver load_details_observer(new_contents);
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(contents(), "last_opened_window.location.hash='foo';"));
capturer.Wait();
load_details_observer.Wait();
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_TRUE(controller.GetLastCommittedEntry());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_TRUE(load_details_observer.load_details().is_same_document);
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
InitialNavigationEntryStatus_MainFrame) {
GURL main_window_url(embedded_test_server()->GetURL("/title1.html"));
GURL no_commit_url(embedded_test_server()->GetURL("/page204.html"));
GURL cross_document_url(embedded_test_server()->GetURL("/title2.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_window_url));
{
Shell* new_shell = OpenWindow(contents(), GURL());
WebContentsImpl* new_contents =
static_cast<WebContentsImpl*>(new_shell->web_contents());
NavigationControllerImpl& controller = new_contents->GetController();
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* last_entry = controller.GetLastCommittedEntry();
EXPECT_TRUE(last_entry->IsInitialEntry());
EXPECT_EQ(InitialNavigationEntryState::kInitialForSynchronousAboutBlank,
last_entry->initial_navigation_entry_state());
EXPECT_EQ(GURL("about:blank"), last_entry->GetURL());
GURL same_document_url("about:blank#foo");
FrameTreeNode* root = new_contents->GetPrimaryFrameTree().root();
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(NavigateToURL(new_contents, same_document_url));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(last_entry, controller.GetLastCommittedEntry());
last_entry = controller.GetLastCommittedEntry();
EXPECT_TRUE(last_entry->IsInitialEntry());
EXPECT_EQ(InitialNavigationEntryState::kInitialForSynchronousAboutBlank,
last_entry->initial_navigation_entry_state());
EXPECT_EQ(same_document_url, last_entry->GetURL());
}
{
Shell* new_shell = OpenWindow(contents(), GURL());
WebContentsImpl* new_contents =
static_cast<WebContentsImpl*>(new_shell->web_contents());
NavigationControllerImpl& controller = new_contents->GetController();
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* last_entry = controller.GetLastCommittedEntry();
EXPECT_TRUE(last_entry->IsInitialEntry());
EXPECT_EQ(InitialNavigationEntryState::kInitialForSynchronousAboutBlank,
last_entry->initial_navigation_entry_state());
EXPECT_EQ(GURL("about:blank"), last_entry->GetURL());
FrameTreeNode* root = new_contents->GetPrimaryFrameTree().root();
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(NavigateToURL(new_contents, cross_document_url));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_FALSE(capturer.is_same_document());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_NE(last_entry, controller.GetLastCommittedEntry());
last_entry = controller.GetLastCommittedEntry();
EXPECT_FALSE(last_entry->IsInitialEntry());
EXPECT_EQ(InitialNavigationEntryState::kNonInitial,
last_entry->initial_navigation_entry_state());
EXPECT_EQ(cross_document_url, last_entry->GetURL());
}
{
Shell* new_shell = OpenWindow(contents(), no_commit_url);
WebContentsImpl* new_contents =
static_cast<WebContentsImpl*>(new_shell->web_contents());
new_contents->Stop();
NavigationControllerImpl& controller = new_contents->GetController();
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* last_entry = controller.GetLastCommittedEntry();
EXPECT_TRUE(last_entry->IsInitialEntry());
EXPECT_EQ(InitialNavigationEntryState::kInitialNotForSynchronousAboutBlank,
last_entry->initial_navigation_entry_state());
EXPECT_EQ(GURL(), last_entry->GetURL());
FrameTreeNode* root = new_contents->GetPrimaryFrameTree().root();
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(NavigateToURL(new_contents, cross_document_url));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_FALSE(capturer.is_same_document());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_NE(last_entry, controller.GetLastCommittedEntry());
last_entry = controller.GetLastCommittedEntry();
EXPECT_FALSE(last_entry->IsInitialEntry());
EXPECT_EQ(InitialNavigationEntryState::kNonInitial,
last_entry->initial_navigation_entry_state());
EXPECT_EQ(cross_document_url, last_entry->GetURL());
}
{
Shell* new_shell = OpenWindow(contents(), GURL());
WebContentsImpl* new_contents =
static_cast<WebContentsImpl*>(new_shell->web_contents());
NavigationControllerImpl& controller = new_contents->GetController();
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* last_entry = controller.GetLastCommittedEntry();
EXPECT_TRUE(last_entry->IsInitialEntry());
EXPECT_EQ(InitialNavigationEntryState::kInitialForSynchronousAboutBlank,
last_entry->initial_navigation_entry_state());
EXPECT_EQ(GURL("about:blank"), last_entry->GetURL());
FrameTreeNode* root = new_contents->GetPrimaryFrameTree().root();
FrameNavigateParamsCapturer capturer(root);
root->current_frame_host()->Reload();
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_FALSE(capturer.is_same_document());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(last_entry, controller.GetLastCommittedEntry());
last_entry = controller.GetLastCommittedEntry();
EXPECT_TRUE(last_entry->IsInitialEntry());
EXPECT_EQ(InitialNavigationEntryState::kInitialForSynchronousAboutBlank,
last_entry->initial_navigation_entry_state());
EXPECT_EQ(GURL("about:blank"), last_entry->GetURL());
}
{
Shell* new_shell = OpenWindow(contents(), no_commit_url);
WebContentsImpl* new_contents =
static_cast<WebContentsImpl*>(new_shell->web_contents());
new_contents->Stop();
NavigationControllerImpl& controller = new_contents->GetController();
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* last_entry = controller.GetLastCommittedEntry();
EXPECT_TRUE(last_entry->IsInitialEntry());
EXPECT_EQ(InitialNavigationEntryState::kInitialNotForSynchronousAboutBlank,
last_entry->initial_navigation_entry_state());
EXPECT_EQ(GURL(), last_entry->GetURL());
FrameTreeNode* root = new_contents->GetPrimaryFrameTree().root();
FrameNavigateParamsCapturer capturer(root);
root->current_frame_host()->Reload();
EXPECT_FALSE(root->navigation_request());
EXPECT_FALSE(new_contents->GetController().GetPendingEntry());
EXPECT_TRUE(
ExecJs(root, "location.href = '" + cross_document_url.spec() + "';"));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_FALSE(capturer.is_same_document());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_NE(last_entry, controller.GetLastCommittedEntry());
last_entry = controller.GetLastCommittedEntry();
EXPECT_FALSE(last_entry->IsInitialEntry());
EXPECT_EQ(InitialNavigationEntryState::kNonInitial,
last_entry->initial_navigation_entry_state());
EXPECT_EQ(cross_document_url, last_entry->GetURL());
}
{
Shell* new_shell = OpenWindow(contents(), GURL());
WebContentsImpl* new_contents =
static_cast<WebContentsImpl*>(new_shell->web_contents());
NavigationControllerImpl& controller = new_contents->GetController();
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* last_entry = controller.GetLastCommittedEntry();
EXPECT_TRUE(last_entry->IsInitialEntry());
EXPECT_EQ(InitialNavigationEntryState::kInitialForSynchronousAboutBlank,
last_entry->initial_navigation_entry_state());
EXPECT_EQ(GURL("about:blank"), last_entry->GetURL());
FrameTreeNode* root = new_contents->GetPrimaryFrameTree().root();
FrameNavigateParamsCapturer capturer(root);
ASSERT_TRUE(ExecJs(root, "location.reload()"));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_FALSE(capturer.is_same_document());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(last_entry, controller.GetLastCommittedEntry());
last_entry = controller.GetLastCommittedEntry();
EXPECT_TRUE(last_entry->IsInitialEntry());
EXPECT_EQ(InitialNavigationEntryState::kInitialForSynchronousAboutBlank,
last_entry->initial_navigation_entry_state());
EXPECT_EQ(GURL("about:blank"), last_entry->GetURL());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
InitialNavigationEntryStatus_SubframeAndRestore) {
GURL main_window_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
GURL no_commit_url(embedded_test_server()->GetURL("/page204.html"));
GURL subframe_url(embedded_test_server()->GetURL("/title1.html"));
GURL subframe_url_2(embedded_test_server()->GetURL("/title2.html"));
GURL subframe_url_3(embedded_test_server()->GetURL("/title3.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_window_url));
Shell* new_shell = OpenWindow(contents(), no_commit_url);
WebContentsImpl* new_contents =
static_cast<WebContentsImpl*>(new_shell->web_contents());
new_contents->Stop();
NavigationControllerImpl& controller = new_contents->GetController();
NavigationEntryImpl* last_entry = controller.GetLastCommittedEntry();
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_TRUE(last_entry->IsInitialEntry());
EXPECT_EQ(GURL(), last_entry->GetURL());
{
CreateSubframe(new_contents, "child_frame", subframe_url,
true );
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(last_entry, controller.GetLastCommittedEntry());
EXPECT_TRUE(last_entry->IsInitialEntry());
ASSERT_EQ(1U, last_entry->root_node()->children.size());
EXPECT_EQ(subframe_url,
last_entry->root_node()->children[0]->frame_entry->url());
EXPECT_EQ(InitialNavigationEntryState::kInitialNotForSynchronousAboutBlank,
last_entry->initial_navigation_entry_state());
EXPECT_EQ(GURL(), last_entry->GetURL());
}
FrameTreeNode* root = new_contents->GetPrimaryFrameTree().root();
FrameTreeNode* child = root->child_at(0);
{
{
FrameNavigateParamsCapturer capturer(child);
NavigateFrameToURL(child, subframe_url_2);
capturer.Wait();
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
EXPECT_EQ(subframe_url_2, child->current_url());
}
EXPECT_EQ(1, controller.GetEntryCount());
last_entry = controller.GetLastCommittedEntry();
EXPECT_TRUE(last_entry->IsInitialEntry());
EXPECT_EQ(InitialNavigationEntryState::kInitialNotForSynchronousAboutBlank,
last_entry->initial_navigation_entry_state());
EXPECT_EQ(GURL(), last_entry->GetURL());
EXPECT_EQ(subframe_url_2,
last_entry->root_node()->children[0]->frame_entry->url());
{
FrameNavigateParamsCapturer capturer(child);
EXPECT_TRUE(
ExecJs(child, "location.href = '" + subframe_url_3.spec() + "';"));
capturer.Wait();
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
EXPECT_EQ(subframe_url_3, child->current_url());
}
EXPECT_EQ(1, controller.GetEntryCount());
last_entry = controller.GetLastCommittedEntry();
EXPECT_TRUE(last_entry->IsInitialEntry());
EXPECT_EQ(InitialNavigationEntryState::kInitialNotForSynchronousAboutBlank,
last_entry->initial_navigation_entry_state());
EXPECT_EQ(GURL(), last_entry->GetURL());
EXPECT_EQ(subframe_url_3,
last_entry->root_node()->children[0]->frame_entry->url());
}
{
FrameNavigateParamsCapturer capturer(child);
ASSERT_TRUE(ExecJs(child, "location.reload()"));
capturer.Wait();
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
EXPECT_EQ(subframe_url_3, child->current_url());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(last_entry, controller.GetLastCommittedEntry());
EXPECT_TRUE(last_entry->IsInitialEntry());
EXPECT_EQ(InitialNavigationEntryState::kInitialNotForSynchronousAboutBlank,
last_entry->initial_navigation_entry_state());
EXPECT_EQ(GURL(), last_entry->GetURL());
EXPECT_EQ(subframe_url_3,
last_entry->root_node()->children[0]->frame_entry->url());
}
{
child->current_frame_host()->Reload();
EXPECT_FALSE(root->navigation_request());
EXPECT_FALSE(child->navigation_request());
EXPECT_FALSE(new_contents->GetController().GetPendingEntry());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(last_entry, controller.GetLastCommittedEntry());
EXPECT_TRUE(last_entry->IsInitialEntry());
EXPECT_EQ(InitialNavigationEntryState::kInitialNotForSynchronousAboutBlank,
last_entry->initial_navigation_entry_state());
FrameNavigateParamsCapturer capturer(child);
EXPECT_TRUE(
ExecJs(child, "location.href = '" + subframe_url_2.spec() + "';"));
capturer.Wait();
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
EXPECT_EQ(subframe_url_2, child->current_url());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(last_entry, controller.GetLastCommittedEntry());
last_entry = controller.GetLastCommittedEntry();
EXPECT_TRUE(last_entry->IsInitialEntry());
EXPECT_EQ(InitialNavigationEntryState::kInitialNotForSynchronousAboutBlank,
last_entry->initial_navigation_entry_state());
EXPECT_EQ(GURL(), last_entry->GetURL());
EXPECT_EQ(subframe_url_2,
last_entry->root_node()->children[0]->frame_entry->url());
}
{
Shell* restore_shell =
Shell::CreateNewWindow(controller.GetBrowserContext(),
GURL::EmptyGURL(), nullptr, gfx::Size());
NavigationControllerImpl& restore_controller =
static_cast<NavigationControllerImpl&>(
restore_shell->web_contents()->GetController());
restore_controller.CopyStateFrom(&controller, false );
EXPECT_EQ(1, restore_controller.GetEntryCount());
EXPECT_EQ(0, restore_controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* restored_entry =
restore_controller.GetLastCommittedEntry();
EXPECT_TRUE(restored_entry->IsInitialEntry());
EXPECT_EQ(InitialNavigationEntryState::kInitialNotForSynchronousAboutBlank,
restored_entry->initial_navigation_entry_state());
EXPECT_EQ(GURL(), restored_entry->root_node()->frame_entry->url());
ASSERT_EQ(1U, restored_entry->root_node()->children.size());
EXPECT_EQ(subframe_url_2,
restored_entry->root_node()->children[0]->frame_entry->url());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
NavigationTypeClassification_ClientSideRedirect) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
EXPECT_TRUE(NavigateToURL(shell(), GURL(url::kAboutBlankURL)));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(1, controller.GetEntryCount());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
{
FrameNavigateParamsCapturer capturer(root);
capturer.set_navigations_remaining(2);
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/client_redirect.html"));
NavigateFrameToURL(root, frame_url);
capturer.Wait();
ASSERT_EQ(2U, capturer.transitions().size());
ASSERT_EQ(2U, capturer.navigation_types().size());
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transitions()[0], ui::PAGE_TRANSITION_LINK));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY,
capturer.navigation_types()[0]);
EXPECT_FALSE(capturer.did_replace_entries()[0]);
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transitions()[1],
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY,
capturer.navigation_types()[1]);
EXPECT_TRUE(capturer.did_replace_entries()[1]);
EXPECT_EQ(2, controller.GetEntryCount());
}
{
GURL fragment_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html#foo"));
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(contents(), "location.href = '#foo'"));
capturer.Wait();
EXPECT_EQ(fragment_url, contents()->GetLastCommittedURL());
ASSERT_EQ(1U, capturer.transitions().size());
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transitions()[0], ui::PAGE_TRANSITION_LINK));
EXPECT_FALSE(capturer.did_replace_entries()[0]);
EXPECT_EQ(3, controller.GetEntryCount());
}
{
GURL fragment_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html#foobar"));
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(contents(), "location.replace('#foobar');"));
capturer.Wait();
EXPECT_EQ(fragment_url, contents()->GetLastCommittedURL());
ASSERT_EQ(1U, capturer.transitions().size());
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transitions()[0],
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
EXPECT_TRUE(capturer.did_replace_entries()[0]);
EXPECT_EQ(3, controller.GetEntryCount());
}
{
GURL push_state_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html#bar"));
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(
ExecJs(shell(), "history.pushState({}, '', 'simple_page_1.html#bar')"));
capturer.Wait();
EXPECT_EQ(push_state_url, contents()->GetLastCommittedURL());
ASSERT_EQ(1U, capturer.transitions().size());
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transitions()[0],
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
EXPECT_FALSE(capturer.did_replace_entries()[0]);
EXPECT_EQ(4, controller.GetEntryCount());
}
{
GURL replace_state_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html#bar2"));
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(
shell(), "history.replaceState({}, '', 'simple_page_1.html#bar2')"));
capturer.Wait();
EXPECT_EQ(replace_state_url, contents()->GetLastCommittedURL());
ASSERT_EQ(1U, capturer.transitions().size());
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transitions()[0],
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
EXPECT_TRUE(capturer.did_replace_entries()[0]);
EXPECT_EQ(4, controller.GetEntryCount());
}
{
GURL fragment_url_2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html#baz"));
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(NavigateToURL(shell(), fragment_url_2));
capturer.Wait();
ASSERT_EQ(1U, capturer.transitions().size());
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transitions()[0],
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
EXPECT_FALSE(capturer.did_replace_entries()[0]);
EXPECT_EQ(5, controller.GetEntryCount());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
LoadCommittedDetails_IsSameDocument) {
GURL links_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_links.html"));
EXPECT_TRUE(NavigateToURL(shell(), links_url));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
{
FrameNavigateParamsCapturer capturer(root);
std::string script = "document.getElementById('fraglink').click()";
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_LINK));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.is_same_document());
}
{
FrameNavigateParamsCapturer capturer(root);
std::string script = "document.getElementById('thelink').click()";
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_LINK));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_FALSE(capturer.is_same_document());
}
GURL iframe_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe.html"));
EXPECT_TRUE(NavigateToURL(shell(), iframe_url));
root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(1U, root->child_count());
ASSERT_NE(nullptr, root->child_at(0));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), links_url));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
std::string script = "document.getElementById('fraglink').click()";
EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
EXPECT_TRUE(capturer.is_same_document());
}
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
std::string script = "document.getElementById('thelink').click()";
EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
EXPECT_FALSE(capturer.is_same_document());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_BlankAutoSubframe) {
GURL about_blank_url(url::kAboutBlankURL);
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
url::Origin main_origin =
root->current_frame_host()->GetLastCommittedOrigin();
EXPECT_EQ(url::Origin::Create(main_url), main_origin);
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, kAddEmptyFrameScript));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(main_url, entry->GetURL());
scoped_refptr<FrameNavigationEntry> root_entry =
entry->root_node()->frame_entry.get();
EXPECT_EQ(main_url, root_entry->url());
EXPECT_EQ(main_origin, root_entry->committed_origin());
EXPECT_FALSE(root_entry->initiator_origin().has_value());
ASSERT_EQ(1U, entry->root_node()->children.size());
scoped_refptr<FrameNavigationEntry> frame_entry =
entry->root_node()->children[0]->frame_entry.get();
EXPECT_EQ(about_blank_url, frame_entry->url());
EXPECT_EQ(main_origin, frame_entry->committed_origin());
ASSERT_TRUE(frame_entry->initiator_origin().has_value());
EXPECT_EQ(main_origin, frame_entry->initiator_origin().value());
EXPECT_TRUE(root->child_at(0)->is_on_initial_empty_document());
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root->child_at(0), kAddEmptyFrameScript));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
ASSERT_EQ(1U, entry->root_node()->children[0]->children.size());
frame_entry = entry->root_node()->children[0]->children[0]->frame_entry.get();
EXPECT_EQ(about_blank_url, frame_entry->url());
EXPECT_EQ(main_origin, frame_entry->committed_origin());
ASSERT_TRUE(frame_entry->initiator_origin().has_value());
EXPECT_EQ(main_origin, frame_entry->initiator_origin().value());
EXPECT_TRUE(root->child_at(0)->child_at(0)->is_on_initial_empty_document());
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, JsReplace(kAddFrameWithSrcScript, "about:blank")));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(entry, controller.GetLastCommittedEntry());
ASSERT_EQ(2U, entry->root_node()->children.size());
frame_entry = entry->root_node()->children[1]->frame_entry.get();
EXPECT_EQ(about_blank_url, frame_entry->url());
EXPECT_EQ(main_origin, frame_entry->committed_origin());
ASSERT_TRUE(frame_entry->initiator_origin().has_value());
EXPECT_EQ(main_origin, frame_entry->initiator_origin().value());
EXPECT_TRUE(root->child_at(1)->is_on_initial_empty_document());
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
{
LoadCommittedCapturer capturer(root->child_at(0)->child_at(0));
std::string script = JsReplace(
"var frames = document.getElementsByTagName('iframe');"
"frames[0].src = $1;",
frame_url);
EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(entry, controller.GetLastCommittedEntry());
ASSERT_EQ(1U, entry->root_node()->children[0]->children.size());
frame_entry = entry->root_node()->children[0]->children[0]->frame_entry.get();
EXPECT_EQ(frame_url, frame_entry->url());
EXPECT_EQ(url::Origin::Create(frame_url), frame_entry->committed_origin());
ASSERT_TRUE(frame_entry->initiator_origin().has_value());
EXPECT_EQ(main_origin, frame_entry->initiator_origin().value());
EXPECT_TRUE(root->child_at(0)->is_on_initial_empty_document());
EXPECT_FALSE(root->child_at(0)->child_at(0)->is_on_initial_empty_document());
EXPECT_TRUE(root->child_at(1)->is_on_initial_empty_document());
GURL foo_url(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_2.html"));
{
LoadCommittedCapturer capturer(root->child_at(1));
std::string script = JsReplace(
"var frames = document.getElementsByTagName('iframe');"
"frames[1].src = $1;",
foo_url);
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(entry, controller.GetLastCommittedEntry());
ASSERT_EQ(2U, entry->root_node()->children.size());
frame_entry = entry->root_node()->children[1]->frame_entry.get();
EXPECT_EQ(foo_url, frame_entry->url());
EXPECT_EQ(url::Origin::Create(foo_url), frame_entry->committed_origin());
ASSERT_TRUE(frame_entry->initiator_origin().has_value());
EXPECT_EQ(main_origin, frame_entry->initiator_origin().value());
EXPECT_TRUE(root->child_at(0)->is_on_initial_empty_document());
EXPECT_FALSE(root->child_at(0)->child_at(0)->is_on_initial_empty_document());
EXPECT_FALSE(root->child_at(1)->is_on_initial_empty_document());
EXPECT_EQ(frame_entry->committed_origin(),
root->child_at(1)->current_frame_host()->GetLastCommittedOrigin());
{
LoadCommittedCapturer capturer(root->child_at(0)->child_at(0));
std::string script =
"var frames = document.getElementsByTagName('iframe');"
"frames[0].src = 'about:blank';";
EXPECT_TRUE(ExecJs(root->child_at(0), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
}
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_NE(entry, controller.GetLastCommittedEntry());
NavigationEntryImpl* entry2 = controller.GetLastCommittedEntry();
ASSERT_EQ(2U, entry->root_node()->children.size());
EXPECT_EQ(entry->root_node()->frame_entry.get(),
entry2->root_node()->frame_entry.get());
EXPECT_EQ(entry->root_node()->children[0]->frame_entry.get(),
entry2->root_node()->children[0]->frame_entry.get());
EXPECT_EQ(entry->root_node()->children[1]->frame_entry.get(),
entry2->root_node()->children[1]->frame_entry.get());
EXPECT_NE(entry->root_node()->children[0]->children[0]->frame_entry.get(),
entry2->root_node()->children[0]->children[0]->frame_entry.get());
frame_entry =
entry2->root_node()->children[0]->children[0]->frame_entry.get();
EXPECT_EQ(about_blank_url, frame_entry->url());
EXPECT_EQ(main_origin, frame_entry->committed_origin());
ASSERT_TRUE(frame_entry->initiator_origin().has_value());
EXPECT_EQ(main_origin, frame_entry->initiator_origin().value());
EXPECT_TRUE(root->child_at(0)->is_on_initial_empty_document());
EXPECT_FALSE(root->child_at(0)->child_at(0)->is_on_initial_empty_document());
EXPECT_FALSE(root->child_at(1)->is_on_initial_empty_document());
if (AreAllSitesIsolatedForTesting()) {
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site A ------- proxies for B\n"
" | +--Site A -- proxies for B\n"
" +--Site B ------- proxies for A\n"
"Where A = http://127.0.0.1/\n"
" B = http://foo.com/",
DepictFrameTree(*root));
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_SlowNestedAutoSubframe) {
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL slow_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
TestNavigationManager subframe_delayer(shell()->web_contents(), slow_url);
std::string script_template =
"var iframe = document.createElement('iframe');"
"iframe.src = $1;"
"document.body.appendChild(iframe);";
EXPECT_TRUE(ExecJs(root, JsReplace(script_template, slow_url)));
EXPECT_TRUE(subframe_delayer.WaitForRequestStart());
shell()->web_contents()->Stop();
GURL foo_url(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(ExecJs(root->child_at(0), JsReplace(script_template, foo_url)));
WaitForLoadStopWithoutSuccessCheck(shell()->web_contents());
EXPECT_EQ(foo_url, root->child_at(0)->child_at(0)->current_url());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
DISABLED_PushStatePreservesPendingEntry) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL stalled_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
TestNavigationManager stalled_navigation(shell()->web_contents(),
stalled_url);
controller.LoadURL(stalled_url, Referrer(), ui::PAGE_TRANSITION_LINK,
std::string());
EXPECT_TRUE(stalled_navigation.WaitForRequestStart());
NavigationEntryImpl* entry = controller.GetPendingEntry();
ASSERT_NE(nullptr, entry);
EXPECT_EQ(stalled_url, entry->GetURL());
{
FrameNavigateParamsCapturer capturer(root);
capturer.set_wait_for_load(false);
std::string script = "history.pushState({}, '', 'pushed')";
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.is_same_document());
}
entry = controller.GetPendingEntry();
ASSERT_NE(nullptr, entry);
EXPECT_EQ(stalled_url, entry->GetURL());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
ReplaceStatePreservesPendingEntry) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL stalled_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
TestNavigationManager stalled_navigation(shell()->web_contents(),
stalled_url);
controller.LoadURL(stalled_url, Referrer(), ui::PAGE_TRANSITION_LINK,
std::string());
EXPECT_TRUE(stalled_navigation.WaitForRequestStart());
NavigationEntryImpl* entry = controller.GetPendingEntry();
ASSERT_NE(nullptr, entry);
EXPECT_EQ(stalled_url, entry->GetURL());
{
FrameNavigateParamsCapturer capturer(root);
capturer.set_wait_for_load(false);
std::string script = "history.replaceState({}, '', 'replaced')";
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_TRUE(capturer.is_same_document());
}
entry = controller.GetPendingEntry();
ASSERT_NE(nullptr, entry);
EXPECT_EQ(stalled_url, entry->GetURL());
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
DISABLED_FrameNavigationEntry_NoCommitNestedAutoSubframe) {
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL no_commit_url(embedded_test_server()->GetURL("/nocontent"));
{
std::string script =
"var iframe = document.createElement('iframe');"
"iframe.src = '" +
no_commit_url.spec() +
"';"
"document.body.appendChild(iframe);";
EXPECT_TRUE(ExecJs(root, script));
}
EXPECT_EQ(GURL(), root->child_at(0)->current_url());
GURL foo_url(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_1.html"));
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(
ExecJs(root->child_at(0), JsReplace(kAddFrameWithSrcScript, foo_url)));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
EXPECT_EQ(foo_url, root->child_at(0)->child_at(0)->current_url());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_BackNestedAutoSubframe) {
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
{
FrameNavigateParamsCapturer capturer(root);
std::string script = "history.pushState({}, 'foo', 'foo')";
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.is_same_document());
}
GURL child_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, JsReplace(kAddFrameWithSrcScript, child_url)));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
{
TestNavigationObserver back_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoBack();
back_load_observer.Wait();
}
GURL grandchild_url(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_1.html"));
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root->child_at(0),
JsReplace(kAddFrameWithSrcScript, grandchild_url)));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
EXPECT_EQ(grandchild_url, root->child_at(0)->child_at(0)->current_url());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_BackForwardAcrossSubframeCreation) {
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
{
FrameNavigateParamsCapturer capturer(root);
std::string script = "history.pushState({}, 'foo', 'foo')";
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.is_same_document());
}
GURL blank_url(url::kAboutBlankURL);
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, JsReplace(kAddFrameWithSrcScript, blank_url)));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
EXPECT_TRUE(ExecJs(root->child_at(0), "foo=3;"));
}
{
TestNavigationObserver back_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoBack();
back_load_observer.Wait();
}
{
TestNavigationObserver forward_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoForward();
forward_load_observer.Wait();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
}
EXPECT_EQ(3, EvalJs(root->child_at(0), "foo"));
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
FrameNavigationEntry_BackForwardAcrossSubframeCreationCrossDocument) {
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
{
FrameNavigateParamsCapturer capturer(root);
std::string script = "history.pushState({}, 'foo', 'foo')";
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.is_same_document());
}
GURL child_url1(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, JsReplace(kAddFrameWithSrcScript, child_url1)));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
EXPECT_TRUE(ExecJs(root->child_at(0), "foo=3;"));
}
GURL child_url2(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/page_with_links.html"));
{
LoadCommittedCapturer capturer(root->child_at(0));
std::string script = JsReplace("frames[0].location = $1;", child_url2);
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
}
EXPECT_EQ(child_url2, root->child_at(0)->current_url());
{
TestNavigationObserver back_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoBack();
back_load_observer.Wait();
}
EXPECT_EQ(child_url1, root->child_at(0)->current_url());
{
TestNavigationObserver back_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoBack();
back_load_observer.Wait();
}
EXPECT_EQ(child_url1, root->child_at(0)->current_url());
{
TestNavigationObserver forward_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoToOffset(2);
forward_load_observer.Wait();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
}
EXPECT_EQ(child_url2, root->child_at(0)->current_url());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_BackSameDocumentThenNestedBlank) {
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
{
FrameNavigateParamsCapturer capturer(root);
std::string script = "history.pushState({}, 'foo', 'foo')";
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.is_same_document());
}
GURL child_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, JsReplace(kAddFrameWithSrcScript, child_url)));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
GURL grandchild_url(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_1.html"));
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root->child_at(0),
JsReplace(kAddFrameWithSrcScript, grandchild_url)));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
{
TestNavigationObserver back_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoBack();
back_load_observer.Wait();
}
{
FrameNavigateParamsCapturer capturer(root->child_at(0)->child_at(0));
std::string script = "frames[0][0].location.href = 'about:blank'";
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
EXPECT_FALSE(capturer.is_same_document());
}
EXPECT_EQ(GURL(url::kAboutBlankURL),
root->child_at(0)->child_at(0)->current_url());
EXPECT_EQ(
root->current_frame_host()->GetSiteInstance(),
root->child_at(0)->child_at(0)->current_frame_host()->GetSiteInstance());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_RenameNestedAutoSubframe) {
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL child_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, JsReplace(kAddFrameWithSrcScript, child_url)));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
EXPECT_TRUE(ExecJs(root->child_at(0), "window.name = 'foo';"));
GURL bar_url(embedded_test_server()->GetURL(
"bar.com", "/navigation_controller/simple_page_1.html"));
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(
ExecJs(root->child_at(0), JsReplace(kAddFrameWithSrcScript, bar_url)));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
EXPECT_EQ(bar_url, root->child_at(0)->child_at(0)->current_url());
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
FrameNavigationEntry_CrossProcessSameDocumentNavigation) {
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL child_url(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_2.html"));
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, JsReplace(kAddFrameWithSrcScript, child_url)));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
GURL grandchild_url(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_1.html"));
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root->child_at(0),
JsReplace(kAddFrameWithSrcScript, grandchild_url)));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
NavigationEntryImpl* entry_before_nav = controller.GetLastCommittedEntry();
scoped_refptr<FrameNavigationEntry> main_entry_before_nav =
entry_before_nav->GetFrameEntry(root);
scoped_refptr<FrameNavigationEntry> child_entry_before_nav =
entry_before_nav->GetFrameEntry(root->child_at(0));
scoped_refptr<FrameNavigationEntry> grandchild_entry_before_nav =
entry_before_nav->GetFrameEntry(root->child_at(0)->child_at(0));
ASSERT_NE(main_entry_before_nav, nullptr);
ASSERT_NE(child_entry_before_nav, nullptr);
ASSERT_NE(grandchild_entry_before_nav, nullptr);
GURL child_fragment_url(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_2.html#fragment"));
{
LoadCommittedCapturer capturer(root->child_at(0));
std::string script =
JsReplace("frames[0].location = $1;", child_fragment_url);
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
}
NavigationEntryImpl* entry_after_nav = controller.GetLastCommittedEntry();
EXPECT_EQ(main_entry_before_nav, entry_after_nav->GetFrameEntry(root));
EXPECT_NE(child_entry_before_nav,
entry_after_nav->GetFrameEntry(root->child_at(0)));
EXPECT_EQ(child_fragment_url,
entry_after_nav->GetFrameEntry(root->child_at(0))->url());
EXPECT_EQ(grandchild_entry_before_nav,
entry_after_nav->GetFrameEntry(root->child_at(0)->child_at(0)));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_AutoSubframe) {
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, JsReplace(kAddFrameWithSrcScript, frame_url)));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(main_url, entry->GetURL());
scoped_refptr<FrameNavigationEntry> root_entry =
entry->root_node()->frame_entry.get();
EXPECT_EQ(main_url, root_entry->url());
EXPECT_FALSE(root_entry->initiator_origin().has_value());
EXPECT_FALSE(controller.GetPendingEntry());
ASSERT_EQ(1U, entry->root_node()->children.size());
scoped_refptr<FrameNavigationEntry> frame_entry =
entry->root_node()->children[0]->frame_entry.get();
EXPECT_EQ(frame_url, frame_entry->url());
ASSERT_TRUE(frame_entry->initiator_origin().has_value());
EXPECT_EQ(url::Origin::Create(main_url),
frame_entry->initiator_origin().value());
EXPECT_FALSE(root->child_at(0)->is_on_initial_empty_document());
GURL foo_url(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_1.html"));
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, JsReplace(kAddFrameWithSrcScript, foo_url)));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
EXPECT_EQ(1, controller.GetEntryCount());
entry = controller.GetLastCommittedEntry();
EXPECT_EQ(main_url, entry->GetURL());
root_entry = entry->root_node()->frame_entry.get();
EXPECT_EQ(main_url, root_entry->url());
EXPECT_FALSE(root_entry->initiator_origin().has_value());
EXPECT_FALSE(controller.GetPendingEntry());
ASSERT_EQ(2U, entry->root_node()->children.size());
frame_entry = entry->root_node()->children[1]->frame_entry.get();
EXPECT_EQ(foo_url, frame_entry->url());
ASSERT_TRUE(frame_entry->initiator_origin().has_value());
EXPECT_EQ(url::Origin::Create(main_url),
frame_entry->initiator_origin().value());
EXPECT_FALSE(root->child_at(1)->is_on_initial_empty_document());
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(
ExecJs(root->child_at(1), JsReplace(kAddFrameWithSrcScript, foo_url)));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
EXPECT_EQ(1, controller.GetEntryCount());
entry = controller.GetLastCommittedEntry();
EXPECT_EQ(main_url, entry->GetURL());
root_entry = entry->root_node()->frame_entry.get();
EXPECT_EQ(main_url, root_entry->url());
EXPECT_FALSE(root_entry->initiator_origin().has_value());
ASSERT_EQ(2U, entry->root_node()->children.size());
ASSERT_EQ(1U, entry->root_node()->children[1]->children.size());
frame_entry = entry->root_node()->children[1]->children[0]->frame_entry.get();
EXPECT_EQ(foo_url, frame_entry->url());
ASSERT_TRUE(frame_entry->initiator_origin().has_value());
EXPECT_EQ(url::Origin::Create(foo_url),
frame_entry->initiator_origin().value());
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, JsReplace(kAddFrameWithSrcScript, foo_url)));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
EXPECT_EQ(1, controller.GetEntryCount());
entry = controller.GetLastCommittedEntry();
EXPECT_EQ(main_url, entry->GetURL());
root_entry = entry->root_node()->frame_entry.get();
EXPECT_EQ(main_url, root_entry->url());
EXPECT_FALSE(root_entry->initiator_origin().has_value());
ASSERT_EQ(3U, entry->root_node()->children.size());
frame_entry = entry->root_node()->children[2]->frame_entry.get();
EXPECT_EQ(foo_url, frame_entry->url());
ASSERT_TRUE(frame_entry->initiator_origin().has_value());
EXPECT_EQ(url::Origin::Create(main_url),
frame_entry->initiator_origin().value());
{
LoadCommittedCapturer capturer(shell()->web_contents());
FrameTreeNode* child = root->child_at(2);
EXPECT_TRUE(ExecJs(child, JsReplace(kAddFrameWithSrcScript, frame_url)));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
EXPECT_EQ(1, controller.GetEntryCount());
entry = controller.GetLastCommittedEntry();
EXPECT_EQ(main_url, entry->GetURL());
root_entry = entry->root_node()->frame_entry.get();
EXPECT_EQ(main_url, root_entry->url());
EXPECT_FALSE(root_entry->initiator_origin().has_value());
ASSERT_EQ(1U, entry->root_node()->children[2]->children.size());
frame_entry = entry->root_node()->children[2]->children[0]->frame_entry.get();
EXPECT_EQ(frame_url, frame_entry->url());
ASSERT_TRUE(frame_entry->initiator_origin().has_value());
EXPECT_EQ(url::Origin::Create(foo_url),
frame_entry->initiator_origin().value());
if (AreAllSitesIsolatedForTesting()) {
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site A ------- proxies for B\n"
" |--Site B ------- proxies for A\n"
" | +--Site B -- proxies for A\n"
" +--Site B ------- proxies for A\n"
" +--Site A -- proxies for B\n"
"Where A = http://127.0.0.1/\n"
" B = http://foo.com/",
DepictFrameTree(*root));
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_NewSubframe) {
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, JsReplace(kAddFrameWithSrcScript, frame_url)));
capturer.Wait();
}
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
GURL frame_url2(embedded_test_server()->GetURL(
"/navigation_controller/page_with_links.html"));
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url2));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
}
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry2 = controller.GetLastCommittedEntry();
EXPECT_NE(entry, entry2);
EXPECT_EQ(main_url, entry2->GetURL());
scoped_refptr<FrameNavigationEntry> root_entry2 =
entry2->root_node()->frame_entry.get();
EXPECT_EQ(entry->root_node()->frame_entry.get(), root_entry2);
EXPECT_EQ(main_url, root_entry2->url());
EXPECT_FALSE(root_entry2->initiator_origin().has_value());
ASSERT_EQ(1U, entry2->root_node()->children.size());
EXPECT_NE(entry->root_node()->children[0]->frame_entry.get(),
entry2->root_node()->children[0]->frame_entry.get());
EXPECT_EQ(frame_url2, entry2->root_node()->children[0]->frame_entry->url());
GURL foo_url(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_1.html"));
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, JsReplace(kAddFrameWithSrcScript, foo_url)));
capturer.Wait();
}
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(
ExecJs(root->child_at(1), JsReplace(kAddFrameWithSrcScript, foo_url)));
capturer.Wait();
}
GURL bar_url(embedded_test_server()->GetURL(
"bar.com", "/navigation_controller/simple_page_1.html"));
{
FrameNavigateParamsCapturer capturer(root->child_at(1)->child_at(0));
RenderFrameDeletedObserver deleted_observer(
root->child_at(1)->child_at(0)->current_frame_host());
EXPECT_TRUE(
NavigateToURLFromRenderer(root->child_at(1)->child_at(0), bar_url));
if (AreAllSitesIsolatedForTesting())
deleted_observer.WaitUntilDeleted();
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
}
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry3 = controller.GetLastCommittedEntry();
EXPECT_NE(entry, entry3);
EXPECT_EQ(main_url, entry3->GetURL());
scoped_refptr<FrameNavigationEntry> root_entry3 =
entry3->root_node()->frame_entry.get();
EXPECT_EQ(main_url, root_entry3->url());
EXPECT_EQ(root_entry2, root_entry3);
ASSERT_EQ(2U, entry3->root_node()->children.size());
EXPECT_EQ(entry2->root_node()->children[0]->frame_entry.get(),
entry3->root_node()->children[0]->frame_entry.get());
EXPECT_EQ(entry2->root_node()->children[1]->frame_entry.get(),
entry3->root_node()->children[1]->frame_entry.get());
EXPECT_NE(entry2->root_node()->children[1]->children[0]->frame_entry.get(),
entry3->root_node()->children[1]->children[0]->frame_entry.get());
EXPECT_EQ(foo_url, entry3->root_node()->children[1]->frame_entry->url());
ASSERT_EQ(1U, entry3->root_node()->children[1]->children.size());
EXPECT_EQ(bar_url,
entry3->root_node()->children[1]->children[0]->frame_entry->url());
GURL baz_url(embedded_test_server()->GetURL(
"baz.com", "/navigation_controller/simple_page_1.html"));
{
FrameNavigateParamsCapturer capturer(root->child_at(1));
RenderFrameDeletedObserver deleted_observer(
root->child_at(1)->current_frame_host());
std::string script =
"var frames = document.getElementsByTagName('iframe');"
"frames[1].src = '" +
baz_url.spec() + "';";
EXPECT_TRUE(ExecJs(root, script));
if (AreAllSitesIsolatedForTesting())
deleted_observer.WaitUntilDeleted();
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
}
EXPECT_EQ(4, controller.GetEntryCount());
EXPECT_EQ(3, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry4 = controller.GetLastCommittedEntry();
EXPECT_NE(entry, entry4);
EXPECT_EQ(main_url, entry4->GetURL());
scoped_refptr<FrameNavigationEntry> root_entry4 =
entry4->root_node()->frame_entry.get();
EXPECT_EQ(root_entry3, root_entry4);
EXPECT_EQ(main_url, root_entry4->url());
ASSERT_EQ(2U, entry4->root_node()->children.size());
EXPECT_EQ(entry3->root_node()->children[0]->frame_entry.get(),
entry4->root_node()->children[0]->frame_entry.get());
EXPECT_EQ(baz_url, entry4->root_node()->children[1]->frame_entry->url());
ASSERT_EQ(0U, entry4->root_node()->children[1]->children.size());
if (AreAllSitesIsolatedForTesting()) {
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site A ------- proxies for B\n"
" +--Site B ------- proxies for A\n"
"Where A = http://127.0.0.1/\n"
" B = http://baz.com/",
DepictFrameTree(*root));
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_SubframeAfterSameDocument) {
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(1U, root->child_count());
ASSERT_NE(nullptr, root->child_at(0));
GURL subframe_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
{
LoadCommittedCapturer capturer(root->child_at(0));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), subframe_url));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
std::string push_script = "history.pushState({}, 'page 2', 'page_2.html')";
EXPECT_TRUE(ExecJs(root, push_script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
ASSERT_EQ(1U, entry->root_node()->children.size());
EXPECT_EQ(subframe_url, entry->root_node()->children[0]->frame_entry->url());
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root->child_at(0),
JsReplace(kAddFrameWithSrcScript, subframe_url)));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
entry = controller.GetLastCommittedEntry();
ASSERT_EQ(1U, entry->root_node()->children.size());
EXPECT_EQ(subframe_url, entry->root_node()->children[0]->frame_entry->url());
ASSERT_EQ(1U, entry->root_node()->children[0]->children.size());
EXPECT_EQ(subframe_url,
entry->root_node()->children[0]->children[0]->frame_entry->url());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_SubframeBackForward) {
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, JsReplace(kAddFrameWithSrcScript, frame_url)));
capturer.Wait();
}
NavigationEntryImpl* entry1 = controller.GetLastCommittedEntry();
GURL frame_url2(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/page_with_links.html"));
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url2));
capturer.Wait();
}
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry2 = controller.GetLastCommittedEntry();
GURL frame_url3(embedded_test_server()->GetURL(
"bar.com", "/navigation_controller/page_with_links.html"));
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url3));
capturer.Wait();
}
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry3 = controller.GetLastCommittedEntry();
EXPECT_EQ(entry1->root_node()->frame_entry.get(),
entry2->root_node()->frame_entry.get());
EXPECT_EQ(entry2->root_node()->frame_entry.get(),
entry3->root_node()->frame_entry.get());
EXPECT_NE(entry1->root_node()->children[0]->frame_entry.get(),
entry2->root_node()->children[0]->frame_entry.get());
EXPECT_NE(entry1->root_node()->children[0]->frame_entry.get(),
entry3->root_node()->children[0]->frame_entry.get());
EXPECT_NE(entry2->root_node()->children[0]->frame_entry.get(),
entry3->root_node()->children[0]->frame_entry.get());
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
shell()->web_contents()->GetController().GoBack();
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
}
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(entry2, controller.GetLastCommittedEntry());
ASSERT_EQ(1U, entry2->root_node()->children.size());
EXPECT_EQ(frame_url2, entry2->root_node()->children[0]->frame_entry->url());
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
shell()->web_contents()->GetController().GoBack();
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
}
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(entry1, controller.GetLastCommittedEntry());
ASSERT_EQ(1U, entry1->root_node()->children.size());
EXPECT_EQ(frame_url, entry1->root_node()->children[0]->frame_entry->url());
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
shell()->web_contents()->GetController().GoForward();
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
}
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(entry2, controller.GetLastCommittedEntry());
ASSERT_EQ(1U, entry2->root_node()->children.size());
EXPECT_EQ(frame_url2, entry2->root_node()->children[0]->frame_entry->url());
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
shell()->web_contents()->GetController().GoForward();
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
}
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(entry3, controller.GetLastCommittedEntry());
ASSERT_EQ(1U, entry3->root_node()->children.size());
EXPECT_EQ(frame_url3, entry3->root_node()->children[0]->frame_entry->url());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_RecreatedSubframeBackForward) {
GURL initial_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), initial_url));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(initial_url, root->current_url());
NavigationEntryImpl* entry1 = controller.GetLastCommittedEntry();
EXPECT_EQ(0U, entry1->root_node()->children.size());
GURL main_url_a(embedded_test_server()->GetURL(
"a.com", "/navigation_controller/page_with_data_iframe.html"));
GURL data_url("data:text/html,Subframe");
EXPECT_TRUE(NavigateToURL(shell(), main_url_a));
ASSERT_EQ(1U, root->child_count());
ASSERT_EQ(0U, root->child_at(0)->child_count());
EXPECT_EQ(main_url_a, root->current_url());
EXPECT_EQ(data_url, root->child_at(0)->current_url());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry2 = controller.GetLastCommittedEntry();
ASSERT_EQ(1U, entry2->root_node()->children.size());
EXPECT_EQ(data_url, entry2->root_node()->children[0]->frame_entry->url());
EXPECT_EQ(entry2->root_node()
->frame_entry->committed_origin()
->GetTupleOrPrecursorTupleIfOpaque(),
entry2->root_node()
->children[0]
->frame_entry->committed_origin()
->GetTupleOrPrecursorTupleIfOpaque());
ASSERT_TRUE(entry2->root_node()
->children[0]
->frame_entry->initiator_origin()
.has_value());
EXPECT_EQ(url::Origin::Create(main_url_a),
entry2->root_node()
->children[0]
->frame_entry->initiator_origin()
.value());
GURL frame_url_b(embedded_test_server()->GetURL(
"b.com", "/navigation_controller/page_with_data_iframe.html"));
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url_b));
capturer.Wait();
}
ASSERT_EQ(1U, root->child_count());
EXPECT_EQ(main_url_a, root->current_url());
EXPECT_EQ(frame_url_b, root->child_at(0)->current_url());
EXPECT_EQ(data_url, root->child_at(0)->child_at(0)->current_url());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry3 = controller.GetLastCommittedEntry();
ASSERT_EQ(1U, entry3->root_node()->children.size());
ASSERT_EQ(1U, entry3->root_node()->children[0]->children.size());
EXPECT_EQ(entry2->root_node()->frame_entry.get(),
entry3->root_node()->frame_entry.get());
EXPECT_NE(entry2->root_node()->children[0]->frame_entry.get(),
entry3->root_node()->children[0]->frame_entry.get());
EXPECT_EQ(frame_url_b, entry3->root_node()->children[0]->frame_entry->url());
EXPECT_EQ(data_url,
entry3->root_node()->children[0]->children[0]->frame_entry->url());
EXPECT_EQ(entry3->root_node()
->children[0]
->frame_entry->committed_origin()
->GetTupleOrPrecursorTupleIfOpaque(),
entry3->root_node()
->children[0]
->children[0]
->frame_entry->committed_origin()
->GetTupleOrPrecursorTupleIfOpaque());
GURL frame_url_c(embedded_test_server()->GetURL(
"c.com", "/navigation_controller/simple_page_2.html"));
{
FrameNavigateParamsCapturer capturer(root->child_at(0)->child_at(0));
EXPECT_TRUE(
NavigateToURLFromRenderer(root->child_at(0)->child_at(0), frame_url_c));
capturer.Wait();
}
ASSERT_EQ(1U, root->child_count());
EXPECT_EQ(main_url_a, root->current_url());
EXPECT_EQ(frame_url_b, root->child_at(0)->current_url());
EXPECT_EQ(frame_url_c, root->child_at(0)->child_at(0)->current_url());
EXPECT_EQ(4, controller.GetEntryCount());
EXPECT_EQ(3, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry4 = controller.GetLastCommittedEntry();
ASSERT_EQ(1U, entry4->root_node()->children.size());
ASSERT_EQ(1U, entry4->root_node()->children[0]->children.size());
EXPECT_EQ(entry3->root_node()->frame_entry.get(),
entry4->root_node()->frame_entry.get());
EXPECT_EQ(entry3->root_node()->children[0]->frame_entry.get(),
entry4->root_node()->children[0]->frame_entry.get());
EXPECT_NE(entry3->root_node()->children[0]->children[0]->frame_entry.get(),
entry4->root_node()->children[0]->children[0]->frame_entry.get());
EXPECT_EQ(frame_url_b, entry4->root_node()->children[0]->frame_entry->url());
EXPECT_EQ(frame_url_c,
entry4->root_node()->children[0]->children[0]->frame_entry->url());
int64_t root_dsn =
entry4->root_node()->frame_entry->document_sequence_number();
int64_t frame_b_dsn =
entry4->root_node()->children[0]->frame_entry->document_sequence_number();
int64_t frame_c_dsn = entry4->root_node()
->children[0]
->children[0]
->frame_entry->document_sequence_number();
GURL main_url_d(embedded_test_server()->GetURL(
"d.com", "/navigation_controller/simple_page_2.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url_d));
ASSERT_EQ(0U, root->child_count());
EXPECT_EQ(main_url_d, root->current_url());
EXPECT_EQ(5, controller.GetEntryCount());
EXPECT_EQ(4, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry5 = controller.GetLastCommittedEntry();
EXPECT_EQ(0U, entry5->root_node()->children.size());
{
TestNavigationObserver back_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoBack();
back_load_observer.Wait();
}
ASSERT_EQ(1U, root->child_count());
ASSERT_EQ(1U, root->child_at(0)->child_count());
EXPECT_EQ(main_url_a, root->current_url());
EXPECT_EQ(frame_url_b, root->child_at(0)->current_url());
EXPECT_EQ(frame_url_c, root->child_at(0)->child_at(0)->current_url());
EXPECT_EQ(5, controller.GetEntryCount());
EXPECT_EQ(3, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(entry4, controller.GetLastCommittedEntry());
EXPECT_EQ(root_dsn,
entry4->root_node()->frame_entry->document_sequence_number());
ASSERT_EQ(1U, entry4->root_node()->children.size());
ASSERT_EQ(1U, entry4->root_node()->children[0]->children.size());
EXPECT_EQ(frame_url_b, entry4->root_node()->children[0]->frame_entry->url());
EXPECT_EQ(frame_url_c,
entry4->root_node()->children[0]->children[0]->frame_entry->url());
EXPECT_EQ(frame_b_dsn, entry4->root_node()
->children[0]
->frame_entry->document_sequence_number());
EXPECT_EQ(frame_c_dsn, entry4->root_node()
->children[0]
->children[0]
->frame_entry->document_sequence_number());
EXPECT_TRUE(ExecJs(root, "foo=3;"));
{
TestNavigationObserver back_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoBack();
back_load_observer.Wait();
}
ASSERT_EQ(1U, root->child_count());
ASSERT_EQ(1U, root->child_at(0)->child_count());
EXPECT_EQ(main_url_a, root->current_url());
EXPECT_EQ(frame_url_b, root->child_at(0)->current_url());
EXPECT_EQ(data_url, root->child_at(0)->child_at(0)->current_url());
EXPECT_EQ(5, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(entry3, controller.GetLastCommittedEntry());
ASSERT_EQ(1U, entry3->root_node()->children.size());
ASSERT_EQ(1U, entry3->root_node()->children[0]->children.size());
EXPECT_EQ(frame_url_b, entry3->root_node()->children[0]->frame_entry->url());
EXPECT_EQ(data_url,
entry3->root_node()->children[0]->children[0]->frame_entry->url());
EXPECT_EQ(entry3->root_node()
->children[0]
->frame_entry->committed_origin()
->GetTupleOrPrecursorTupleIfOpaque(),
entry3->root_node()
->children[0]
->children[0]
->frame_entry->committed_origin()
->GetTupleOrPrecursorTupleIfOpaque());
EXPECT_EQ(3, EvalJs(root, "foo"));
{
TestNavigationObserver back_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoBack();
back_load_observer.Wait();
}
ASSERT_EQ(1U, root->child_count());
ASSERT_EQ(0U, root->child_at(0)->child_count());
EXPECT_EQ(main_url_a, root->current_url());
EXPECT_EQ(data_url, root->child_at(0)->current_url());
EXPECT_EQ(5, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(entry2, controller.GetLastCommittedEntry());
ASSERT_EQ(1U, entry2->root_node()->children.size());
EXPECT_EQ(data_url, entry2->root_node()->children[0]->frame_entry->url());
EXPECT_EQ(entry2->root_node()
->frame_entry->committed_origin()
->GetTupleOrPrecursorTupleIfOpaque(),
entry2->root_node()
->children[0]
->frame_entry->committed_origin()
->GetTupleOrPrecursorTupleIfOpaque());
ASSERT_TRUE(entry2->root_node()
->children[0]
->frame_entry->initiator_origin()
.has_value());
EXPECT_EQ(url::Origin::Create(main_url_a),
entry2->root_node()
->children[0]
->frame_entry->initiator_origin()
.value());
{
TestNavigationObserver back_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoBack();
back_load_observer.Wait();
}
ASSERT_EQ(0U, root->child_count());
EXPECT_EQ(initial_url, root->current_url());
EXPECT_EQ(5, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(entry1, controller.GetLastCommittedEntry());
EXPECT_EQ(0U, entry1->root_node()->children.size());
{
TestNavigationObserver back_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoToOffset(2);
back_load_observer.Wait();
}
ASSERT_EQ(1U, root->child_count());
EXPECT_EQ(main_url_a, root->current_url());
EXPECT_EQ(frame_url_b, root->child_at(0)->current_url());
EXPECT_EQ(data_url, root->child_at(0)->child_at(0)->current_url());
EXPECT_EQ(5, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(entry3, controller.GetLastCommittedEntry());
ASSERT_EQ(1U, entry3->root_node()->children.size());
EXPECT_EQ(frame_url_b, entry3->root_node()->children[0]->frame_entry->url());
EXPECT_EQ(data_url,
entry3->root_node()->children[0]->children[0]->frame_entry->url());
EXPECT_EQ(entry3->root_node()
->children[0]
->frame_entry->committed_origin()
->GetTupleOrPrecursorTupleIfOpaque(),
entry3->root_node()
->children[0]
->children[0]
->frame_entry->committed_origin()
->GetTupleOrPrecursorTupleIfOpaque());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_SubframeHistoryFallback) {
GURL main_url_a(embedded_test_server()->GetURL(
"a.com", "/navigation_controller/page_with_data_iframe.html"));
GURL data_url("data:text/html,Subframe");
EXPECT_TRUE(NavigateToURL(shell(), main_url_a));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(1U, root->child_count());
ASSERT_EQ(0U, root->child_at(0)->child_count());
EXPECT_EQ(main_url_a, root->current_url());
EXPECT_EQ(data_url, root->child_at(0)->current_url());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry1 = controller.GetLastCommittedEntry();
ASSERT_EQ(1U, entry1->root_node()->children.size());
EXPECT_EQ(data_url, entry1->root_node()->children[0]->frame_entry->url());
GURL frame_url_b(embedded_test_server()->GetURL(
"b.com", "/navigation_controller/simple_page_1.html"));
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url_b));
capturer.Wait();
}
ASSERT_EQ(1U, root->child_count());
EXPECT_EQ(main_url_a, root->current_url());
EXPECT_EQ(frame_url_b, root->child_at(0)->current_url());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry2 = controller.GetLastCommittedEntry();
ASSERT_EQ(1U, entry2->root_node()->children.size());
EXPECT_EQ(entry1->root_node()->frame_entry.get(),
entry2->root_node()->frame_entry.get());
EXPECT_NE(entry1->root_node()->children[0]->frame_entry.get(),
entry2->root_node()->children[0]->frame_entry.get());
EXPECT_EQ(frame_url_b, entry2->root_node()->children[0]->frame_entry->url());
GURL main_url_c(embedded_test_server()->GetURL(
"c.com", "/navigation_controller/simple_page_2.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url_c));
ASSERT_EQ(0U, root->child_count());
EXPECT_EQ(main_url_c, root->current_url());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry3 = controller.GetLastCommittedEntry();
EXPECT_EQ(0U, entry3->root_node()->children.size());
entry2->root_node()->children[0]->frame_entry->set_frame_unique_name("wrong");
DisableBackForwardCacheForTesting(contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
{
TestNavigationObserver back_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoBack();
back_load_observer.Wait();
}
ASSERT_EQ(1U, root->child_count());
EXPECT_EQ(main_url_a, root->current_url());
EXPECT_EQ(data_url, root->child_at(0)->current_url());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(entry2, controller.GetLastCommittedEntry());
ASSERT_EQ(2U, entry2->root_node()->children.size());
EXPECT_EQ(frame_url_b, entry2->root_node()->children[0]->frame_entry->url());
EXPECT_EQ(data_url, entry2->root_node()->children[1]->frame_entry->url());
}
class DataUrlCommitObserver : public WebContentsObserver {
public:
explicit DataUrlCommitObserver(WebContents* web_contents)
: WebContentsObserver(web_contents),
message_loop_runner_(new MessageLoopRunner) {}
void Wait() { message_loop_runner_->Run(); }
private:
void DidFinishNavigation(NavigationHandle* navigation_handle) override {
if (navigation_handle->HasCommitted() &&
!navigation_handle->IsErrorPage() &&
navigation_handle->GetURL().scheme() == "data")
message_loop_runner_->Quit();
}
scoped_refptr<MessageLoopRunner> message_loop_runner_;
};
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_DynamicSubframeHistoryFallback) {
GURL main_url_a(embedded_test_server()->GetURL(
"a.com", "/navigation_controller/dynamic_iframe.html"));
{
DataUrlCommitObserver data_observer(shell()->web_contents());
EXPECT_TRUE(NavigateToURL(shell(), main_url_a));
data_observer.Wait();
}
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(1U, root->child_count());
ASSERT_EQ(0U, root->child_at(0)->child_count());
EXPECT_EQ(main_url_a, root->current_url());
EXPECT_EQ("data", root->child_at(0)->current_url().scheme());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry1 = controller.GetLastCommittedEntry();
ASSERT_EQ(1U, entry1->root_node()->children.size());
EXPECT_EQ("data",
entry1->root_node()->children[0]->frame_entry->url().scheme());
GURL main_url_b(embedded_test_server()->GetURL(
"b.com", "/navigation_controller/simple_page_2.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url_b));
ASSERT_EQ(0U, root->child_count());
EXPECT_EQ(main_url_b, root->current_url());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry2 = controller.GetLastCommittedEntry();
EXPECT_EQ(0U, entry2->root_node()->children.size());
DisableBackForwardCacheForTesting(contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
{
DataUrlCommitObserver back_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoBack();
back_load_observer.Wait();
}
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
ASSERT_EQ(1U, root->child_count());
EXPECT_EQ(main_url_a, root->current_url());
EXPECT_EQ("data", root->child_at(0)->current_url().scheme());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(entry1, controller.GetLastCommittedEntry());
ASSERT_EQ(1U, entry1->root_node()->children.size());
EXPECT_EQ("data",
entry1->root_node()->children[0]->frame_entry->url().scheme());
EXPECT_TRUE(shell()->web_contents()->GetController().CanGoForward());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_RecreatedBlankSubframe) {
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/inject_into_blank_iframe.html"));
GURL blank_url(url::kAboutBlankURL);
EXPECT_TRUE(NavigateToURL(shell(), main_url));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(1U, root->child_count());
ASSERT_EQ(0U, root->child_at(0)->child_count());
EXPECT_EQ(main_url, root->current_url());
EXPECT_EQ(blank_url, root->child_at(0)->current_url());
EXPECT_EQ("Injected text",
EvalJs(root->child_at(0), "document.body.innerHTML"));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
ASSERT_EQ(1U, entry->root_node()->children.size());
scoped_refptr<FrameNavigationEntry> child_frame_entry =
entry->root_node()->children[0]->frame_entry.get();
EXPECT_EQ(blank_url, child_frame_entry->url());
GURL main_url_2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url_2));
ASSERT_EQ(0U, root->child_count());
EXPECT_EQ(main_url_2, root->current_url());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
{
TestNavigationObserver back_load_observer(shell()->web_contents());
controller.GoBack();
back_load_observer.Wait();
}
ASSERT_EQ(1U, root->child_count());
EXPECT_EQ(main_url, root->current_url());
EXPECT_EQ(blank_url, root->child_at(0)->current_url());
EXPECT_EQ("Injected text",
EvalJs(root->child_at(0), "document.body.innerHTML"));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(entry, controller.GetLastCommittedEntry());
ASSERT_EQ(1U, entry->root_node()->children.size());
EXPECT_EQ(child_frame_entry,
entry->root_node()->children[0]->frame_entry.get());
EXPECT_EQ(blank_url, entry->root_node()->children[0]->frame_entry->url());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_RecreatedInjectedBlankSubframe) {
DisableBackForwardCacheForTesting(shell()->web_contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/inject_subframe_into_blank_iframe.html"));
GURL blank_url(url::kAboutBlankURL);
GURL inner_url(
embedded_test_server()->GetURL("/navigation_controller/form.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(1U, root->child_count());
ASSERT_EQ(1U, root->child_at(0)->child_count());
ASSERT_EQ(0U, root->child_at(0)->child_at(0)->child_count());
EXPECT_EQ(main_url, root->current_url());
EXPECT_EQ(blank_url, root->child_at(0)->current_url());
EXPECT_EQ(inner_url, root->child_at(0)->child_at(0)->current_url());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
ASSERT_EQ(1U, entry->root_node()->children.size());
scoped_refptr<FrameNavigationEntry> child_frame_entry =
entry->root_node()->children[0]->frame_entry.get();
EXPECT_EQ(blank_url, entry->root_node()->children[0]->frame_entry->url());
EXPECT_EQ(inner_url,
entry->root_node()->children[0]->children[0]->frame_entry->url());
EXPECT_TRUE(ExecJs(root->child_at(0)->child_at(0),
"document.getElementById('itext').value = 'modified';"));
GURL main_url_2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url_2));
ASSERT_EQ(0U, root->child_count());
EXPECT_EQ(main_url_2, root->current_url());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
{
TestNavigationObserver back_load_observer(shell()->web_contents());
controller.GoBack();
back_load_observer.Wait();
}
ASSERT_EQ(1U, root->child_count());
EXPECT_EQ(main_url, root->current_url());
EXPECT_EQ(blank_url, root->child_at(0)->current_url());
EXPECT_EQ(inner_url, root->child_at(0)->child_at(0)->current_url());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(entry, controller.GetLastCommittedEntry());
ASSERT_EQ(1U, root->child_count());
ASSERT_EQ(1U, entry->root_node()->children.size());
EXPECT_NE(child_frame_entry,
entry->root_node()->children[0]->frame_entry.get());
EXPECT_EQ(blank_url, entry->root_node()->children[0]->frame_entry->url());
EXPECT_EQ(inner_url,
entry->root_node()->children[0]->children[0]->frame_entry->url());
EXPECT_EQ("", EvalJs(root->child_at(0)->child_at(0),
"document.getElementById('itext').value"));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_RecreatedInjectedSrcdocSubframe) {
DisableBackForwardCacheForTesting(shell()->web_contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/inject_iframe_srcdoc_with_nested_frame.html"));
GURL inner_url(
embedded_test_server()->GetURL("/navigation_controller/form.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(1U, root->child_count());
ASSERT_EQ(1U, root->child_at(0)->child_count());
ASSERT_EQ(0U, root->child_at(0)->child_at(0)->child_count());
EXPECT_EQ(main_url, root->current_url());
EXPECT_TRUE(root->child_at(0)->current_url().IsAboutSrcdoc());
EXPECT_EQ(inner_url, root->child_at(0)->child_at(0)->current_url());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
ASSERT_EQ(1U, entry->root_node()->children.size());
scoped_refptr<FrameNavigationEntry> child_frame_entry =
entry->root_node()->children[0]->frame_entry.get();
EXPECT_TRUE(
entry->root_node()->children[0]->frame_entry->url().IsAboutSrcdoc());
EXPECT_EQ(inner_url,
entry->root_node()->children[0]->children[0]->frame_entry->url());
EXPECT_TRUE(ExecJs(root->child_at(0)->child_at(0),
"document.getElementById('itext').value = 'modified';"));
GURL main_url_2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url_2));
ASSERT_EQ(0U, root->child_count());
EXPECT_EQ(main_url_2, root->current_url());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
{
TestNavigationObserver back_load_observer(shell()->web_contents());
controller.GoBack();
back_load_observer.Wait();
}
ASSERT_EQ(1U, root->child_count());
ASSERT_EQ(1U, root->child_at(0)->child_count());
ASSERT_EQ(0U, root->child_at(0)->child_at(0)->child_count());
EXPECT_EQ(main_url, root->current_url());
EXPECT_TRUE(root->child_at(0)->current_url().IsAboutSrcdoc());
EXPECT_EQ(inner_url, root->child_at(0)->child_at(0)->current_url());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(entry, controller.GetLastCommittedEntry());
ASSERT_EQ(1U, root->child_count());
ASSERT_EQ(1U, entry->root_node()->children.size());
EXPECT_NE(child_frame_entry,
entry->root_node()->children[0]->frame_entry.get());
EXPECT_TRUE(
entry->root_node()->children[0]->frame_entry->url().IsAboutSrcdoc());
EXPECT_EQ(inner_url,
entry->root_node()->children[0]->children[0]->frame_entry->url());
EXPECT_EQ("", EvalJs(root->child_at(0)->child_at(0),
"document.getElementById('itext').value"));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_RecreatedSubframeToBlank) {
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_data_iframe.html"));
GURL data_url("data:text/html,Subframe");
EXPECT_TRUE(NavigateToURL(shell(), main_url));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(1U, root->child_count());
ASSERT_EQ(0U, root->child_at(0)->child_count());
EXPECT_EQ(main_url, root->current_url());
EXPECT_EQ(data_url, root->child_at(0)->current_url());
GURL blank_url(url::kAboutBlankURL);
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), blank_url));
EXPECT_EQ(blank_url, root->child_at(0)->current_url());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
ASSERT_EQ(1U, entry->root_node()->children.size());
scoped_refptr<FrameNavigationEntry> blank_entry =
entry->root_node()->children[0]->frame_entry.get();
EXPECT_EQ(blank_url, blank_entry->url());
GURL main_url_2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url_2));
ASSERT_EQ(0U, root->child_count());
EXPECT_EQ(main_url_2, root->current_url());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
{
TestNavigationObserver back_load_observer(shell()->web_contents());
controller.GoBack();
back_load_observer.Wait();
}
ASSERT_EQ(1U, root->child_count());
EXPECT_EQ(main_url, root->current_url());
EXPECT_EQ(blank_url, root->child_at(0)->current_url());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(entry, controller.GetLastCommittedEntry());
ASSERT_EQ(1U, entry->root_node()->children.size());
EXPECT_EQ(blank_entry, entry->root_node()->children[0]->frame_entry.get());
EXPECT_EQ(blank_url, entry->root_node()->children[0]->frame_entry->url());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_RemoveRecreatedBlankSubframe) {
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/remove_blank_iframe_on_load.html"));
GURL blank_url(url::kAboutBlankURL);
EXPECT_TRUE(NavigateToURL(shell(), main_url));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(main_url, root->current_url());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
ASSERT_EQ(1U, entry->root_node()->children.size());
EXPECT_EQ(blank_url, entry->root_node()->children[0]->frame_entry->url());
GURL main_url_2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url_2));
ASSERT_EQ(0U, root->child_count());
EXPECT_EQ(main_url_2, root->current_url());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
{
TestNavigationObserver back_load_observer(shell()->web_contents());
controller.GoBack();
back_load_observer.Wait();
}
EXPECT_EQ(main_url, root->current_url());
EXPECT_TRUE(ExecJs(shell(), "console.log('Success');"));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(entry, controller.GetLastCommittedEntry());
ASSERT_EQ(1U, entry->root_node()->children.size());
EXPECT_EQ(blank_url, entry->root_node()->children[0]->frame_entry->url());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_BackWithRedirect) {
DisableBackForwardCacheForTesting(shell()->web_contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
GURL initial_url(
embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
EXPECT_TRUE(NavigateToURL(shell(), initial_url));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(initial_url, root->current_url());
EXPECT_EQ(2U, root->child_count());
NavigationEntryImpl* entry1 = controller.GetLastCommittedEntry();
EXPECT_EQ(2U, entry1->root_node()->children.size());
GURL frame_url(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/page_with_data_iframe.html"));
GURL data_url("data:text/html,Subframe");
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(1), frame_url));
EXPECT_EQ(initial_url, root->current_url());
EXPECT_EQ(frame_url, root->child_at(0)->current_url());
EXPECT_EQ(data_url, root->child_at(0)->child_at(0)->current_url());
EXPECT_EQ(frame_url, root->child_at(1)->current_url());
EXPECT_EQ(data_url, root->child_at(1)->child_at(0)->current_url());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry2 = controller.GetLastCommittedEntry();
NavigationEntryImpl::TreeNode* root_node = entry2->root_node();
ASSERT_EQ(2U, root_node->children.size());
EXPECT_EQ(frame_url, root_node->children[0]->frame_entry->url());
EXPECT_EQ(data_url, root_node->children[0]->children[0]->frame_entry->url());
EXPECT_EQ(frame_url, root_node->children[1]->frame_entry->url());
EXPECT_EQ(data_url, root_node->children[1]->children[0]->frame_entry->url());
GURL frame_redirect_dest_url(embedded_test_server()->GetURL(
"bar.com", "/navigation_controller/page_with_iframe.html"));
GURL blank_url(url::kAboutBlankURL);
{
TestNavigationObserver observer(shell()->web_contents());
std::string script = "history.replaceState({}, '', '/server-redirect?" +
frame_redirect_dest_url.spec() + "')";
EXPECT_TRUE(ExecJs(root->child_at(0), script));
observer.Wait();
}
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
scoped_refptr<FrameNavigationEntry> nested_entry =
entry2->GetFrameEntry(root->child_at(0)->child_at(0));
EXPECT_TRUE(nested_entry);
EXPECT_EQ(data_url, nested_entry->url());
GURL url2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url2));
EXPECT_EQ(4, controller.GetEntryCount());
EXPECT_EQ(3, controller.GetLastCommittedEntryIndex());
{
TestNavigationObserver back_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoBack();
back_load_observer.Wait();
}
EXPECT_EQ(initial_url, root->current_url());
EXPECT_EQ(frame_redirect_dest_url, root->child_at(0)->current_url());
EXPECT_EQ(blank_url, root->child_at(0)->child_at(0)->current_url());
EXPECT_EQ(frame_url, root->child_at(1)->current_url());
EXPECT_EQ(data_url, root->child_at(1)->child_at(0)->current_url());
EXPECT_EQ(4, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(frame_redirect_dest_url,
entry2->GetFrameEntry(root->child_at(0))->url());
EXPECT_EQ(blank_url,
entry2->GetFrameEntry(root->child_at(0)->child_at(0))->url());
EXPECT_EQ(frame_url, entry2->GetFrameEntry(root->child_at(1))->url());
EXPECT_EQ(data_url,
entry2->GetFrameEntry(root->child_at(1)->child_at(0))->url());
{
TestNavigationObserver observer(shell()->web_contents());
std::string script = "history.replaceState({}, '', '/server-redirect?" +
frame_redirect_dest_url.spec() + "')";
EXPECT_TRUE(ExecJs(root->child_at(1), script));
observer.Wait();
}
{
FrameNavigateParamsCapturer capturer(root->child_at(1));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(1), url2));
capturer.Wait();
}
EXPECT_EQ(4, controller.GetEntryCount());
EXPECT_EQ(3, controller.GetLastCommittedEntryIndex());
{
TestNavigationObserver back_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoBack();
back_load_observer.Wait();
}
EXPECT_EQ(initial_url, root->current_url());
EXPECT_EQ(frame_redirect_dest_url, root->child_at(0)->current_url());
EXPECT_EQ(blank_url, root->child_at(0)->child_at(0)->current_url());
EXPECT_EQ(frame_redirect_dest_url, root->child_at(1)->current_url());
EXPECT_EQ(blank_url, root->child_at(1)->child_at(0)->current_url());
EXPECT_EQ(4, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(frame_redirect_dest_url,
entry2->GetFrameEntry(root->child_at(0))->url());
EXPECT_EQ(blank_url,
entry2->GetFrameEntry(root->child_at(0)->child_at(0))->url());
EXPECT_EQ(frame_redirect_dest_url,
entry2->GetFrameEntry(root->child_at(1))->url());
EXPECT_EQ(blank_url,
entry2->GetFrameEntry(root->child_at(1)->child_at(0))->url());
GURL redirect_dest_url(embedded_test_server()->GetURL(
"bar.com", "/navigation_controller/simple_page_2.html"));
{
TestNavigationObserver observer(shell()->web_contents());
std::string script = "history.replaceState({}, '', '/server-redirect?" +
redirect_dest_url.spec() + "')";
EXPECT_TRUE(ExecJs(root, script));
observer.Wait();
}
EXPECT_TRUE(NavigateToURL(shell(), url2));
EXPECT_EQ(4, controller.GetEntryCount());
EXPECT_EQ(3, controller.GetLastCommittedEntryIndex());
{
TestNavigationObserver back_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoBack();
back_load_observer.Wait();
}
EXPECT_EQ(redirect_dest_url, root->current_url());
EXPECT_EQ(0U, root->child_count());
EXPECT_EQ(0U,
controller.GetLastCommittedEntry()->root_node()->children.size());
EXPECT_EQ(4, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_SameOriginBackWithRedirect) {
DisableBackForwardCacheForTesting(shell()->web_contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
GURL initial_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_data_iframe.html"));
EXPECT_TRUE(NavigateToURL(shell(), initial_url));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(initial_url, root->current_url());
EXPECT_EQ(1U, root->child_count());
NavigationEntryImpl* entry1 = controller.GetLastCommittedEntry();
EXPECT_EQ(1U, entry1->root_node()->children.size());
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_data_iframe.html"));
GURL data_url("data:text/html,Subframe");
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url));
EXPECT_EQ(initial_url, root->current_url());
EXPECT_EQ(frame_url, root->child_at(0)->current_url());
EXPECT_EQ(data_url, root->child_at(0)->child_at(0)->current_url());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry2 = controller.GetLastCommittedEntry();
NavigationEntryImpl::TreeNode* root_node = entry2->root_node();
ASSERT_EQ(1U, root_node->children.size());
EXPECT_EQ(frame_url, root_node->children[0]->frame_entry->url());
EXPECT_EQ(data_url, root_node->children[0]->children[0]->frame_entry->url());
GURL frame_redirect_dest_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe.html"));
{
TestNavigationObserver observer(shell()->web_contents());
std::string script = "history.replaceState({}, '', '/server-redirect?" +
frame_redirect_dest_url.spec() + "')";
EXPECT_TRUE(ExecJs(root->child_at(0), script));
observer.Wait();
}
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
scoped_refptr<FrameNavigationEntry> nested_entry =
entry2->GetFrameEntry(root->child_at(0)->child_at(0));
EXPECT_TRUE(nested_entry);
EXPECT_EQ(data_url, nested_entry->url());
GURL url2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url2));
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
{
TestNavigationObserver back_load_observer(shell()->web_contents());
controller.GoBack();
back_load_observer.Wait();
}
GURL blank_url(url::kAboutBlankURL);
EXPECT_EQ(initial_url, root->current_url());
EXPECT_EQ(frame_redirect_dest_url, root->child_at(0)->current_url());
EXPECT_EQ(blank_url, root->child_at(0)->child_at(0)->current_url());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(frame_redirect_dest_url,
entry2->GetFrameEntry(root->child_at(0))->url());
EXPECT_EQ(blank_url,
entry2->GetFrameEntry(root->child_at(0)->child_at(0))->url());
GURL redirect_dest_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
{
TestNavigationObserver observer(shell()->web_contents());
std::string script = "history.replaceState({}, '', '/server-redirect?" +
redirect_dest_url.spec() + "')";
EXPECT_TRUE(ExecJs(root, script));
observer.Wait();
}
EXPECT_TRUE(NavigateToURL(shell(), url2));
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
{
TestNavigationObserver back_load_observer(shell()->web_contents());
controller.GoBack();
back_load_observer.Wait();
}
EXPECT_EQ(redirect_dest_url, root->current_url());
EXPECT_EQ(0U, root->child_count());
EXPECT_EQ(0U, entry2->root_node()->children.size());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_RestoreViaPageState) {
GURL main_url_a(embedded_test_server()->GetURL(
"a.com", "/navigation_controller/page_with_data_iframe.html"));
GURL data_url("data:text/html,Subframe");
EXPECT_TRUE(NavigateToURL(shell(), main_url_a));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(1U, root->child_count());
ASSERT_EQ(0U, root->child_at(0)->child_count());
EXPECT_EQ(main_url_a, root->current_url());
EXPECT_EQ(data_url, root->child_at(0)->current_url());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry1 = controller.GetLastCommittedEntry();
ASSERT_EQ(1U, entry1->root_node()->children.size());
EXPECT_EQ(data_url, entry1->root_node()->children[0]->frame_entry->url());
GURL frame_url_b(embedded_test_server()->GetURL(
"b.com", "/navigation_controller/simple_page_1.html"));
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url_b));
capturer.Wait();
}
ASSERT_EQ(1U, root->child_count());
EXPECT_EQ(main_url_a, root->current_url());
EXPECT_EQ(frame_url_b, root->child_at(0)->current_url());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry2 = controller.GetLastCommittedEntry();
ASSERT_EQ(1U, entry2->root_node()->children.size());
EXPECT_EQ(frame_url_b, entry2->root_node()->children[0]->frame_entry->url());
GURL main_url_c(embedded_test_server()->GetURL(
"c.com", "/navigation_controller/simple_page_2.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url_c));
ASSERT_EQ(0U, root->child_count());
EXPECT_EQ(main_url_c, root->current_url());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry3 = controller.GetLastCommittedEntry();
EXPECT_EQ(0U, entry3->root_node()->children.size());
std::unique_ptr<NavigationEntryImpl> restored_entry =
NavigationEntryImpl::FromNavigationEntry(
NavigationController::CreateNavigationEntry(
main_url_a, Referrer(), absl::nullopt,
absl::nullopt,
ui::PAGE_TRANSITION_RELOAD, false, std::string(),
controller.GetBrowserContext(),
nullptr ));
EXPECT_EQ(0U, restored_entry->root_node()->children.size());
std::unique_ptr<NavigationEntryRestoreContextImpl> context =
std::make_unique<NavigationEntryRestoreContextImpl>();
restored_entry->SetPageState(entry2->GetPageState(), context.get());
EXPECT_EQ(main_url_a, restored_entry->root_node()->frame_entry->url());
ASSERT_EQ(1U, restored_entry->root_node()->children.size());
EXPECT_EQ(frame_url_b,
restored_entry->root_node()->children[0]->frame_entry->url());
std::vector<std::unique_ptr<NavigationEntry>> entries;
entries.push_back(std::move(restored_entry));
Shell* new_shell = Shell::CreateNewWindow(
controller.GetBrowserContext(), GURL::EmptyGURL(), nullptr, gfx::Size());
FrameTreeNode* new_root =
static_cast<WebContentsImpl*>(new_shell->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& new_controller =
static_cast<NavigationControllerImpl&>(
new_shell->web_contents()->GetController());
new_controller.Restore(entries.size() - 1, RestoreType::kRestored, &entries);
ASSERT_EQ(0u, entries.size());
{
TestNavigationObserver restore_observer(new_shell->web_contents());
new_controller.LoadIfNecessary();
restore_observer.Wait();
}
ASSERT_EQ(1U, new_root->child_count());
EXPECT_EQ(main_url_a, new_root->current_url());
EXPECT_EQ(frame_url_b, new_root->child_at(0)->current_url());
EXPECT_EQ(1, new_controller.GetEntryCount());
EXPECT_EQ(0, new_controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* new_entry = new_controller.GetLastCommittedEntry();
EXPECT_EQ(main_url_a, new_entry->root_node()->frame_entry->url());
ASSERT_EQ(1U, new_entry->root_node()->children.size());
EXPECT_EQ(frame_url_b,
new_entry->root_node()->children[0]->frame_entry->url());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_RestoreViaPartialPageState) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/navigation_controller/inject_into_blank_iframe.html"));
GURL blank_url(url::kAboutBlankURL);
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
std::unique_ptr<NavigationEntryImpl> restored_entry =
NavigationEntryImpl::FromNavigationEntry(
NavigationController::CreateNavigationEntry(
main_url, Referrer(), absl::nullopt ,
absl::nullopt,
ui::PAGE_TRANSITION_RELOAD, false, std::string(),
controller.GetBrowserContext(),
nullptr ));
std::unique_ptr<NavigationEntryRestoreContextImpl> context =
std::make_unique<NavigationEntryRestoreContextImpl>();
restored_entry->SetPageState(blink::PageState::CreateFromURL(main_url),
context.get());
EXPECT_EQ(0U, restored_entry->root_node()->children.size());
std::vector<std::unique_ptr<NavigationEntry>> entries;
entries.push_back(std::move(restored_entry));
controller.Restore(entries.size() - 1, RestoreType::kRestored, &entries);
ASSERT_EQ(0u, entries.size());
{
TestNavigationObserver restore_observer(shell()->web_contents());
controller.LoadIfNecessary();
restore_observer.Wait();
}
ASSERT_EQ(1U, root->child_count());
EXPECT_EQ(main_url, root->current_url());
EXPECT_EQ(blank_url, root->child_at(0)->current_url());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* new_entry = controller.GetLastCommittedEntry();
EXPECT_EQ(main_url, new_entry->root_node()->frame_entry->url());
ASSERT_EQ(1U, new_entry->root_node()->children.size());
EXPECT_EQ(blank_url, new_entry->root_node()->children[0]->frame_entry->url());
EXPECT_EQ("Injected text",
EvalJs(root->child_at(0), "document.body.innerHTML"));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
RestoreAndLoadOnUsedNavigationController) {
GURL url_1(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url_2(embedded_test_server()->GetURL("a.com", "/title2.html"));
GURL url_3(embedded_test_server()->GetURL("a.com", "/title3.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_1));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(url_1, root->current_url());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry1 = controller.GetLastCommittedEntry();
std::unique_ptr<NavigationEntryImpl> restored_entry =
NavigationEntryImpl::FromNavigationEntry(
NavigationController::CreateNavigationEntry(
url_1, Referrer(), absl::nullopt ,
absl::nullopt,
ui::PAGE_TRANSITION_RELOAD, false, std::string(),
controller.GetBrowserContext(),
nullptr ));
EXPECT_EQ(0U, restored_entry->root_node()->children.size());
std::unique_ptr<NavigationEntryRestoreContextImpl> context =
std::make_unique<NavigationEntryRestoreContextImpl>();
restored_entry->SetPageState(entry1->GetPageState(), context.get());
Shell* new_shell = Shell::CreateNewWindow(
controller.GetBrowserContext(), GURL::EmptyGURL(), nullptr, gfx::Size());
FrameTreeNode* new_root =
static_cast<WebContentsImpl*>(new_shell->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& new_controller =
static_cast<NavigationControllerImpl&>(
new_shell->web_contents()->GetController());
EXPECT_TRUE(NavigateToURL(new_shell, url_2));
EXPECT_EQ(1, new_controller.GetEntryCount());
EXPECT_EQ(0, new_controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry2 = new_controller.GetLastCommittedEntry();
EXPECT_EQ(url_2, entry2->GetURL());
EXPECT_TRUE(NavigateToURL(new_shell, url_3));
EXPECT_EQ(2, new_controller.GetEntryCount());
EXPECT_EQ(1, new_controller.GetLastCommittedEntryIndex());
EXPECT_EQ(url_3, new_controller.GetLastCommittedEntry()->GetURL());
DisableBackForwardCacheForTesting(new_shell->web_contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
TestNavigationManager back_navigation_manager(new_shell->web_contents(),
url_2);
new_controller.GoBack();
EXPECT_TRUE(back_navigation_manager.WaitForRequestStart());
EXPECT_EQ(entry2, new_controller.GetPendingEntry());
EXPECT_TRUE(new_root->navigation_request());
std::vector<std::unique_ptr<NavigationEntry>> entries;
entries.push_back(std::move(restored_entry));
new_controller.Restore(entries.size() - 1, RestoreType::kRestored, &entries);
EXPECT_EQ(3, new_controller.GetEntryCount());
EXPECT_EQ(0, new_controller.GetLastCommittedEntryIndex());
EXPECT_EQ(url_2, new_controller.GetEntryAtIndex(0)->GetURL());
EXPECT_EQ(url_3, new_controller.GetEntryAtIndex(1)->GetURL());
EXPECT_EQ(url_1, new_controller.GetEntryAtIndex(2)->GetURL());
EXPECT_EQ(entry2, new_controller.GetPendingEntry());
EXPECT_TRUE(new_root->navigation_request());
ASSERT_EQ(0u, entries.size());
{
TestNavigationObserver restore_observer(new_shell->web_contents());
new_controller.LoadIfNecessary();
restore_observer.Wait();
}
EXPECT_EQ(3, new_controller.GetEntryCount());
EXPECT_EQ(0, new_controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* current_entry = new_controller.GetLastCommittedEntry();
EXPECT_EQ(entry2, current_entry);
EXPECT_EQ(url_2, current_entry->GetURL());
EXPECT_EQ(url_2, new_root->current_url());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
RestoreEmptyAndLoadOnUsedNavigationController) {
GURL url_1(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url_2(embedded_test_server()->GetURL("a.com", "/title2.html"));
Shell* new_shell =
Shell::CreateNewWindow(shell()->web_contents()->GetBrowserContext(),
GURL::EmptyGURL(), nullptr, gfx::Size());
FrameTreeNode* new_root =
static_cast<WebContentsImpl*>(new_shell->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& new_controller =
static_cast<NavigationControllerImpl&>(
new_shell->web_contents()->GetController());
EXPECT_TRUE(NavigateToURL(new_shell, url_1));
EXPECT_EQ(1, new_controller.GetEntryCount());
EXPECT_EQ(0, new_controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry1 = new_controller.GetLastCommittedEntry();
EXPECT_EQ(url_1, entry1->GetURL());
EXPECT_TRUE(NavigateToURL(new_shell, url_2));
EXPECT_EQ(2, new_controller.GetEntryCount());
EXPECT_EQ(1, new_controller.GetLastCommittedEntryIndex());
EXPECT_EQ(url_2, new_controller.GetLastCommittedEntry()->GetURL());
DisableBackForwardCacheForTesting(new_shell->web_contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
TestNavigationManager back_navigation_manager(new_shell->web_contents(),
url_1);
new_controller.GoBack();
EXPECT_TRUE(back_navigation_manager.WaitForRequestStart());
EXPECT_EQ(entry1, new_controller.GetPendingEntry());
EXPECT_TRUE(new_root->navigation_request());
std::vector<std::unique_ptr<NavigationEntry>> entries;
new_controller.Restore(-1, RestoreType::kRestored, &entries);
EXPECT_EQ(2, new_controller.GetEntryCount());
EXPECT_EQ(0, new_controller.GetLastCommittedEntryIndex());
EXPECT_EQ(url_1, new_controller.GetEntryAtIndex(0)->GetURL());
EXPECT_EQ(url_2, new_controller.GetEntryAtIndex(1)->GetURL());
EXPECT_EQ(entry1, new_controller.GetPendingEntry());
EXPECT_TRUE(new_root->navigation_request());
ASSERT_EQ(0u, entries.size());
{
TestNavigationObserver restore_observer(new_shell->web_contents());
new_controller.LoadIfNecessary();
restore_observer.Wait();
}
EXPECT_EQ(2, new_controller.GetEntryCount());
EXPECT_EQ(0, new_controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* current_entry = new_controller.GetLastCommittedEntry();
EXPECT_EQ(url_1, current_entry->GetURL());
EXPECT_EQ(url_1, new_root->current_url());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
RestoreEmptyURLEntryAndLoadOnFreshNavigationController) {
GURL about_blank_url(url::kAboutBlankURL);
EXPECT_TRUE(NavigateToURL(shell(), about_blank_url));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(about_blank_url, root->current_url());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry1 = controller.GetLastCommittedEntry();
std::unique_ptr<NavigationEntryImpl> restored_entry =
NavigationEntryImpl::FromNavigationEntry(
NavigationController::CreateNavigationEntry(
GURL(), Referrer(), absl::nullopt ,
absl::nullopt,
ui::PAGE_TRANSITION_RELOAD, false, std::string(),
controller.GetBrowserContext(),
nullptr ));
EXPECT_EQ(0U, restored_entry->root_node()->children.size());
std::unique_ptr<NavigationEntryRestoreContextImpl> context =
std::make_unique<NavigationEntryRestoreContextImpl>();
entry1->SetURL(GURL());
restored_entry->SetPageState(entry1->GetPageState(), context.get());
Shell* new_shell = Shell::CreateNewWindow(
controller.GetBrowserContext(), GURL::EmptyGURL(), nullptr, gfx::Size());
NavigationControllerImpl& new_controller =
static_cast<NavigationControllerImpl&>(
new_shell->web_contents()->GetController());
std::vector<std::unique_ptr<NavigationEntry>> entries;
entries.push_back(std::move(restored_entry));
new_controller.Restore(0, RestoreType::kRestored, &entries);
EXPECT_EQ(0u, entries.size());
EXPECT_EQ(1, new_controller.GetEntryCount());
EXPECT_EQ(0, new_controller.GetLastCommittedEntryIndex());
EXPECT_EQ(about_blank_url, new_controller.GetLastCommittedEntry()->GetURL());
{
TestNavigationObserver restore_observer(new_shell->web_contents());
new_controller.LoadIfNecessary();
restore_observer.Wait();
}
EXPECT_EQ(1, new_controller.GetEntryCount());
EXPECT_EQ(0, new_controller.GetLastCommittedEntryIndex());
EXPECT_EQ(about_blank_url, new_controller.GetLastCommittedEntry()->GetURL());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
RestoreAndAddSubframeDuringPendingBack) {
GURL url_1(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url_2(embedded_test_server()->GetURL("a.com", "/title2.html"));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_TRUE(NavigateToURL(shell(), url_1));
NavigationEntryImpl* entry1 = controller.GetLastCommittedEntry();
EXPECT_TRUE(NavigateToURL(shell(), url_2));
NavigationEntryImpl* entry2 = controller.GetLastCommittedEntry();
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(url_2, root->current_url());
std::unique_ptr<NavigationEntryRestoreContextImpl> context =
std::make_unique<NavigationEntryRestoreContextImpl>();
std::unique_ptr<NavigationEntryImpl> restored_entry1 =
NavigationEntryImpl::FromNavigationEntry(
NavigationController::CreateNavigationEntry(
url_1, Referrer(), absl::nullopt ,
absl::nullopt,
ui::PAGE_TRANSITION_RELOAD, false, std::string(),
controller.GetBrowserContext(),
nullptr ));
restored_entry1->SetPageState(entry1->GetPageState(), context.get());
std::unique_ptr<NavigationEntryImpl> restored_entry2 =
NavigationEntryImpl::FromNavigationEntry(
NavigationController::CreateNavigationEntry(
url_2, Referrer(), absl::nullopt ,
absl::nullopt,
ui::PAGE_TRANSITION_RELOAD, false, std::string(),
controller.GetBrowserContext(),
nullptr ));
restored_entry2->SetPageState(entry2->GetPageState(), context.get());
Shell* new_shell = Shell::CreateNewWindow(
controller.GetBrowserContext(), GURL::EmptyGURL(), nullptr, gfx::Size());
WebContentsImpl* new_web_contents =
static_cast<WebContentsImpl*>(new_shell->web_contents());
NavigationControllerImpl& new_controller =
static_cast<NavigationControllerImpl&>(new_web_contents->GetController());
std::vector<std::unique_ptr<NavigationEntry>> entries;
entries.push_back(std::move(restored_entry1));
entries.push_back(std::move(restored_entry2));
new_controller.Restore(entries.size() - 1, RestoreType::kRestored, &entries);
{
TestNavigationObserver restore_observer(new_shell->web_contents());
new_controller.LoadIfNecessary();
restore_observer.Wait();
}
NavigationEntryImpl* new_entry1 = new_controller.GetEntryAtIndex(0);
NavigationEntryImpl* new_entry2 = new_controller.GetEntryAtIndex(1);
EXPECT_EQ(new_entry2, new_controller.GetLastCommittedEntry());
TestNavigationManager back_navigation_manager(new_shell->web_contents(),
url_1);
new_controller.GoBack();
EXPECT_TRUE(back_navigation_manager.WaitForRequestStart());
EXPECT_EQ(new_entry1, new_controller.GetPendingEntry());
EXPECT_TRUE(new_entry1->IsRestored());
TestNavigationObserver subframe_observer(new_web_contents);
CreateSubframe(new_web_contents, "child", url_2,
false );
subframe_observer.WaitForNavigationFinished();
EXPECT_EQ(new_entry2, new_controller.GetLastCommittedEntry());
EXPECT_EQ(new_entry1, new_controller.GetPendingEntry());
EXPECT_TRUE(new_entry1->IsRestored());
ASSERT_TRUE(back_navigation_manager.WaitForNavigationFinished());
EXPECT_FALSE(new_entry1->IsRestored());
EXPECT_EQ(new_entry1, new_controller.GetLastCommittedEntry());
EXPECT_EQ(2, new_controller.GetEntryCount());
EXPECT_EQ(0, new_controller.GetLastCommittedEntryIndex());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_FrameUniqueName) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_links.html"));
EXPECT_TRUE(NavigateToURL(shell(), url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
SiteInstanceImpl* main_site_instance =
root->current_frame_host()->GetSiteInstance();
scoped_refptr<FrameNavigationEntry> frame_entry =
controller.GetLastCommittedEntry()->GetFrameEntry(root);
EXPECT_EQ("", frame_entry->frame_unique_name());
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, JsReplace(kAddFrameWithSrcScript, url)));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
EXPECT_EQ(frame_entry,
controller.GetLastCommittedEntry()->GetFrameEntry(root));
FrameTreeNode* subframe = root->child_at(0);
EXPECT_EQ(main_site_instance,
subframe->current_frame_host()->GetSiteInstance());
scoped_refptr<FrameNavigationEntry> subframe_entry =
controller.GetLastCommittedEntry()->GetFrameEntry(subframe);
EXPECT_THAT(subframe_entry->frame_unique_name(),
testing::HasSubstr("dynamicFrame"));
{
LoadCommittedCapturer capturer(shell()->web_contents());
std::string script = JsReplace(
"var iframe = document.createElement('iframe');"
"iframe.src = $1;"
"iframe.name = 'foo';"
"document.body.appendChild(iframe);",
url);
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
EXPECT_EQ(frame_entry,
controller.GetLastCommittedEntry()->GetFrameEntry(root));
FrameTreeNode* foo_subframe = root->child_at(1);
EXPECT_EQ(main_site_instance,
foo_subframe->current_frame_host()->GetSiteInstance());
scoped_refptr<FrameNavigationEntry> foo_subframe_entry =
controller.GetLastCommittedEntry()->GetFrameEntry(foo_subframe);
EXPECT_THAT(foo_subframe_entry->frame_unique_name(),
testing::HasSubstr("dynamicFrame"));
GURL bar_url(embedded_test_server()->GetURL(
"bar.com", "/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(foo_subframe, bar_url));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
if (AreStrictSiteInstancesEnabled()) {
EXPECT_NE(main_site_instance,
foo_subframe->current_frame_host()->GetSiteInstance());
} else {
EXPECT_TRUE(main_site_instance->IsDefaultSiteInstance());
EXPECT_EQ(main_site_instance,
foo_subframe->current_frame_host()->GetSiteInstance());
}
foo_subframe_entry =
controller.GetLastCommittedEntry()->GetFrameEntry(foo_subframe);
EXPECT_THAT(foo_subframe_entry->frame_unique_name(),
testing::HasSubstr("dynamicFrame"));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
ReplacedNavigationEntryData_ClientSideRedirect) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/client_redirect.html"));
GURL url2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
{
TestNavigationManager navigation_manager_1(shell()->web_contents(), url1);
TestNavigationManager navigation_manager_2(shell()->web_contents(), url2);
shell()->LoadURL(url1);
ASSERT_TRUE(navigation_manager_1
.WaitForNavigationFinished());
ASSERT_TRUE(navigation_manager_2
.WaitForNavigationFinished());
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry1 = controller.GetEntryAtIndex(0);
ASSERT_EQ(url2, entry1->GetURL());
ASSERT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
entry1->GetTransitionType(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
ASSERT_TRUE(entry1->GetReplacedEntryData().has_value());
EXPECT_EQ(url1, entry1->GetReplacedEntryData()->first_committed_url);
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
entry1->GetReplacedEntryData()->first_transition_type,
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)))
<< base::StringPrintf(
"%X", entry1->GetReplacedEntryData()->first_transition_type);
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
ReplacedNavigationEntryData_LocationReplace) {
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
GURL url2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
{
ASSERT_TRUE(NavigateToURL(shell(), url1));
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry1 = controller.GetEntryAtIndex(0);
ASSERT_EQ(url1, entry1->GetURL());
ASSERT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
entry1->GetTransitionType(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
EXPECT_FALSE(entry1->GetReplacedEntryData().has_value());
}
const base::Time time1 = controller.GetEntryAtIndex(0)->GetTimestamp();
{
FrameNavigateParamsCapturer capturer(root);
std::string script = "location.replace('" + url2.spec() + "')";
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry1 = controller.GetEntryAtIndex(0);
ASSERT_EQ(url2, entry1->GetURL());
ASSERT_NE(time1, entry1->GetTimestamp());
ASSERT_TRUE(entry1->GetReplacedEntryData().has_value());
EXPECT_EQ(url1, entry1->GetReplacedEntryData()->first_committed_url);
EXPECT_EQ(time1, entry1->GetReplacedEntryData()->first_timestamp);
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
entry1->GetReplacedEntryData()->first_transition_type,
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
ReplacedNavigationEntryData_ReplaceState) {
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
GURL url2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
GURL url3(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_3.html"));
{
ASSERT_TRUE(NavigateToURL(shell(), url1));
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry1 = controller.GetEntryAtIndex(0);
ASSERT_EQ(url1, entry1->GetURL());
ASSERT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
entry1->GetTransitionType(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
EXPECT_FALSE(entry1->GetReplacedEntryData().has_value());
}
const base::Time time1 = controller.GetEntryAtIndex(0)->GetTimestamp();
{
FrameNavigateParamsCapturer capturer(root);
std::string script =
"history.replaceState({}, 'page 2', 'simple_page_2.html')";
ASSERT_TRUE(ExecJs(root, script));
capturer.Wait();
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry1 = controller.GetEntryAtIndex(0);
ASSERT_EQ(url2, entry1->GetURL());
ASSERT_NE(time1, entry1->GetTimestamp());
ASSERT_TRUE(entry1->GetReplacedEntryData().has_value());
EXPECT_EQ(url1, entry1->GetReplacedEntryData()->first_committed_url);
EXPECT_EQ(time1, entry1->GetReplacedEntryData()->first_timestamp);
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
entry1->GetReplacedEntryData()->first_transition_type,
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
}
{
FrameNavigateParamsCapturer capturer(root);
ASSERT_TRUE(ExecJs(root, "location.reload()"));
capturer.Wait();
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry1 = controller.GetEntryAtIndex(0);
ASSERT_EQ(url2, entry1->GetURL());
ASSERT_NE(time1, entry1->GetTimestamp());
ASSERT_TRUE(entry1->GetReplacedEntryData().has_value());
EXPECT_EQ(url1, entry1->GetReplacedEntryData()->first_committed_url);
EXPECT_EQ(time1, entry1->GetReplacedEntryData()->first_timestamp);
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
entry1->GetReplacedEntryData()->first_transition_type,
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
}
{
FrameNavigateParamsCapturer capturer(root);
std::string script =
"history.replaceState({}, 'page 3', 'simple_page_3.html')";
ASSERT_TRUE(ExecJs(root, script));
capturer.Wait();
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry1 = controller.GetEntryAtIndex(0);
ASSERT_EQ(url3, entry1->GetURL());
ASSERT_NE(time1, entry1->GetTimestamp());
ASSERT_TRUE(entry1->GetReplacedEntryData().has_value());
EXPECT_EQ(url1, entry1->GetReplacedEntryData()->first_committed_url);
EXPECT_EQ(time1, entry1->GetReplacedEntryData()->first_timestamp);
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
entry1->GetReplacedEntryData()->first_transition_type,
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
ReplacedNavigationEntryData_PushState) {
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
GURL url2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
{
ASSERT_TRUE(NavigateToURL(shell(), url1));
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry1 = controller.GetEntryAtIndex(0);
ASSERT_EQ(url1, entry1->GetURL());
ASSERT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
entry1->GetTransitionType(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
EXPECT_FALSE(entry1->GetReplacedEntryData().has_value());
}
{
FrameNavigateParamsCapturer capturer(root);
std::string script =
"history.pushState({}, 'page 2', 'simple_page_2.html')";
ASSERT_TRUE(ExecJs(root, script));
capturer.Wait();
ASSERT_EQ(2, controller.GetEntryCount());
ASSERT_EQ(url1, controller.GetEntryAtIndex(0)->GetURL());
ASSERT_EQ(url2, controller.GetEntryAtIndex(1)->GetURL());
EXPECT_FALSE(
controller.GetEntryAtIndex(0)->GetReplacedEntryData().has_value());
EXPECT_FALSE(
controller.GetEntryAtIndex(1)->GetReplacedEntryData().has_value());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
ReplacedNavigationEntryData_LocationReload) {
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
{
ASSERT_TRUE(NavigateToURL(shell(), url1));
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry1 = controller.GetEntryAtIndex(0);
ASSERT_EQ(url1, entry1->GetURL());
ASSERT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
entry1->GetTransitionType(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
EXPECT_FALSE(entry1->GetReplacedEntryData().has_value());
}
const base::Time time1 = controller.GetEntryAtIndex(0)->GetTimestamp();
{
FrameNavigateParamsCapturer capturer(root);
ASSERT_TRUE(ExecJs(root, "location.reload()"));
capturer.Wait();
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry1 = controller.GetEntryAtIndex(0);
ASSERT_EQ(url1, entry1->GetURL());
ASSERT_NE(time1, entry1->GetTimestamp());
ASSERT_TRUE(entry1->GetReplacedEntryData().has_value());
EXPECT_EQ(url1, entry1->GetReplacedEntryData()->first_committed_url);
EXPECT_EQ(time1, entry1->GetReplacedEntryData()->first_timestamp);
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
entry1->GetReplacedEntryData()->first_transition_type,
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
ReplacedNavigationEntryData_BackAfterReplaceStateWithRedirect) {
DisableBackForwardCacheForTesting(shell()->web_contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
GURL url2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
GURL redirecting_url_to_url2(
embedded_test_server()->GetURL("/server-redirect?" + url2.spec()));
GURL url3(embedded_test_server()->GetURL("/simple_page.html"));
{
ASSERT_TRUE(NavigateToURL(shell(), url1));
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry1 = controller.GetEntryAtIndex(0);
ASSERT_EQ(url1, entry1->GetURL());
ASSERT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
entry1->GetTransitionType(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
EXPECT_FALSE(entry1->GetReplacedEntryData().has_value());
}
{
FrameNavigateParamsCapturer capturer(root);
std::string script = "history.replaceState({}, 'page 2', '" +
redirecting_url_to_url2.spec() + "')";
ASSERT_TRUE(ExecJs(root, script));
capturer.Wait();
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry1 = controller.GetEntryAtIndex(0);
ASSERT_EQ(redirecting_url_to_url2, entry1->GetURL());
ASSERT_TRUE(entry1->GetReplacedEntryData().has_value());
ASSERT_EQ(url1, entry1->GetReplacedEntryData()->first_committed_url);
}
{
ASSERT_TRUE(NavigateToURL(shell(), url3));
ASSERT_EQ(2, controller.GetEntryCount());
}
{
FrameNavigateParamsCapturer capturer(root);
shell()->web_contents()->GetController().GoBack();
capturer.Wait();
NavigationEntry* entry1 = controller.GetEntryAtIndex(0);
ASSERT_EQ(url2, entry1->GetURL());
ASSERT_TRUE(entry1->GetReplacedEntryData().has_value());
EXPECT_EQ(url1, entry1->GetReplacedEntryData()->first_committed_url);
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
ReplacedNavigationEntryData_Back) {
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
GURL url2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
{
ASSERT_TRUE(NavigateToURL(shell(), url1));
ASSERT_TRUE(NavigateToURL(shell(), url2));
ASSERT_EQ(2, controller.GetEntryCount());
NavigationEntry* entry1 = controller.GetEntryAtIndex(0);
NavigationEntry* entry2 = controller.GetEntryAtIndex(1);
ASSERT_EQ(url1, entry1->GetURL());
ASSERT_EQ(url2, entry2->GetURL());
ASSERT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
entry1->GetTransitionType(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
ASSERT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
entry2->GetTransitionType(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
EXPECT_FALSE(entry1->GetReplacedEntryData().has_value());
EXPECT_FALSE(entry2->GetReplacedEntryData().has_value());
}
const base::Time time1 = controller.GetEntryAtIndex(0)->GetTimestamp();
{
FrameNavigateParamsCapturer capturer(root);
shell()->web_contents()->GetController().GoBack();
capturer.Wait();
NavigationEntry* entry1 = controller.GetEntryAtIndex(0);
NavigationEntry* entry2 = controller.GetEntryAtIndex(1);
ASSERT_EQ(url1, entry1->GetURL());
ASSERT_NE(time1, entry1->GetTimestamp());
ASSERT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
entry1->GetTransitionType(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR |
ui::PAGE_TRANSITION_FORWARD_BACK)));
ASSERT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
entry2->GetTransitionType(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
EXPECT_FALSE(entry1->GetReplacedEntryData().has_value());
EXPECT_FALSE(entry2->GetReplacedEntryData().has_value());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, CloneNamedWindow) {
GURL url_1(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_1));
EXPECT_TRUE(ExecJs(shell(), "window.name = 'foo';"));
GURL url_2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_2));
std::unique_ptr<WebContents> new_tab = shell()->web_contents()->Clone();
WebContentsImpl* new_tab_impl = static_cast<WebContentsImpl*>(new_tab.get());
NavigationController& new_controller = new_tab_impl->GetController();
EXPECT_TRUE(new_controller.IsInitialNavigation());
EXPECT_TRUE(new_controller.NeedsReload());
{
TestNavigationObserver clone_observer(new_tab.get());
new_controller.LoadIfNecessary();
clone_observer.Wait();
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
CloneAndGoBackWithNamedWindow) {
GURL url_1(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_1));
EXPECT_TRUE(ExecJs(shell(), "window.name = 'foo';"));
GURL url_2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_2));
EXPECT_TRUE(ExecJs(shell(), "window.name = '';"));
EXPECT_TRUE(NavigateToURL(shell(), url_1));
std::unique_ptr<WebContents> new_tab = shell()->web_contents()->Clone();
WebContentsImpl* new_tab_impl = static_cast<WebContentsImpl*>(new_tab.get());
NavigationController& new_controller = new_tab_impl->GetController();
EXPECT_TRUE(new_controller.IsInitialNavigation());
EXPECT_TRUE(new_controller.NeedsReload());
{
TestNavigationObserver clone_observer(new_tab.get());
new_controller.LoadIfNecessary();
clone_observer.Wait();
}
{
TestNavigationObserver back_load_observer(new_tab.get());
new_controller.GoBack();
back_load_observer.Wait();
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
BackSameDocumentInNewWindow) {
GURL url_1(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_1));
GURL url_2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html#foo"));
EXPECT_TRUE(NavigateToURL(shell(), url_2));
std::unique_ptr<WebContents> new_tab = shell()->web_contents()->Clone();
WebContentsImpl* new_tab_impl = static_cast<WebContentsImpl*>(new_tab.get());
NavigationController& new_controller = new_tab_impl->GetController();
EXPECT_TRUE(new_controller.IsInitialNavigation());
EXPECT_TRUE(new_controller.NeedsReload());
{
TestNavigationObserver back_load_observer(new_tab.get());
new_controller.GoBack();
back_load_observer.Wait();
}
EXPECT_EQ(url_1, new_controller.GetLastCommittedEntry()->GetURL());
EXPECT_FALSE(new_tab_impl->IsLoading());
NavigationController& controller = shell()->web_contents()->GetController();
RenderProcessHost* process =
shell()->web_contents()->GetPrimaryMainFrame()->GetProcess();
RenderProcessHostWatcher crash_observer(
process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
process->Shutdown(0);
crash_observer.Wait();
{
TestNavigationObserver back_load_observer(shell()->web_contents());
controller.GoBack();
back_load_observer.Wait();
}
EXPECT_EQ(url_1, controller.GetLastCommittedEntry()->GetURL());
EXPECT_FALSE(shell()->web_contents()->IsLoading());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_RepeatCreatedFrame) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_links.html"));
EXPECT_TRUE(NavigateToURL(shell(), url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
SiteInstance* main_site_instance =
root->current_frame_host()->GetSiteInstance();
GURL frame_url(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_1.html"));
std::string script = JsReplace(kAddFrameWithSrcScript, frame_url);
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
FrameTreeNode* subframe = root->child_at(0);
if (AreAllSitesIsolatedForTesting()) {
EXPECT_NE(main_site_instance,
subframe->current_frame_host()->GetSiteInstance());
}
scoped_refptr<FrameNavigationEntry> subframe_entry =
controller.GetLastCommittedEntry()->GetFrameEntry(subframe);
EXPECT_EQ(frame_url, subframe_entry->url());
{
FrameNavigateParamsCapturer capturer(root);
controller.Reload(ReloadType::NORMAL, false);
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_RELOAD));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_FALSE(capturer.is_same_document());
}
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
if (AreAllSitesIsolatedForTesting()) {
EXPECT_NE(main_site_instance,
root->child_at(0)->current_frame_host()->GetSiteInstance());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_SequenceNumbers) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_links.html"));
EXPECT_TRUE(NavigateToURL(shell(), url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
scoped_refptr<FrameNavigationEntry> frame_entry =
controller.GetLastCommittedEntry()->GetFrameEntry(root);
int64_t isn_1 = frame_entry->item_sequence_number();
int64_t dsn_1 = frame_entry->document_sequence_number();
EXPECT_NE(-1, isn_1);
EXPECT_NE(-1, dsn_1);
std::string script = "document.getElementById('fraglink').click()";
EXPECT_TRUE(ExecJs(root, script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
frame_entry = controller.GetLastCommittedEntry()->GetFrameEntry(root);
int64_t isn_2 = frame_entry->item_sequence_number();
int64_t dsn_2 = frame_entry->document_sequence_number();
EXPECT_NE(-1, isn_2);
EXPECT_NE(isn_1, isn_2);
EXPECT_EQ(dsn_1, dsn_2);
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, JsReplace(kAddFrameWithSrcScript, url)));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
}
EXPECT_EQ(frame_entry,
controller.GetLastCommittedEntry()->GetFrameEntry(root));
FrameTreeNode* subframe = root->child_at(0);
scoped_refptr<FrameNavigationEntry> subframe_entry =
controller.GetLastCommittedEntry()->GetFrameEntry(subframe);
int64_t isn_3 = subframe_entry->item_sequence_number();
int64_t dsn_3 = subframe_entry->document_sequence_number();
EXPECT_NE(-1, isn_2);
EXPECT_NE(isn_2, isn_3);
EXPECT_NE(dsn_2, dsn_3);
EXPECT_TRUE(ExecJs(subframe, script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
subframe_entry = controller.GetLastCommittedEntry()->GetFrameEntry(subframe);
int64_t isn_4 = subframe_entry->item_sequence_number();
int64_t dsn_4 = subframe_entry->document_sequence_number();
EXPECT_NE(-1, isn_4);
EXPECT_NE(isn_3, isn_4);
EXPECT_EQ(dsn_3, dsn_4);
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_MainFrameRedirectChain) {
NavigationControllerImpl& controller = contents()->GetController();
GURL final_url(embedded_test_server()->GetURL("/simple_page.html"));
GURL redirecting_url(
embedded_test_server()->GetURL("/server-redirect?/simple_page.html"));
NavigateToURLBlockUntilNavigationsComplete(shell(), redirecting_url, 1);
EXPECT_TRUE(IsLastCommittedEntryOfPageType(contents(), PAGE_TYPE_NORMAL));
EXPECT_TRUE(contents()->GetLastCommittedURL() == final_url);
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(entry->GetRedirectChain().size(), 2u);
EXPECT_EQ(entry->GetRedirectChain()[0], redirecting_url);
EXPECT_EQ(entry->GetRedirectChain()[1], final_url);
EXPECT_FALSE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(entry->GetOriginalRequestURL(), redirecting_url);
ExpectReferrerWithDefaultPolicy(entry, GURL());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_AutoSubFrameRedirectChain) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe_redirect.html"));
GURL iframe_redirect_url(
embedded_test_server()->GetURL("/server-redirect?/simple_page.html"));
GURL iframe_final_url(embedded_test_server()->GetURL("/simple_page.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* main_entry = controller.GetLastCommittedEntry();
EXPECT_EQ(main_entry->GetRedirectChain().size(), 1u);
EXPECT_EQ(main_entry->GetRedirectChain()[0], main_url);
ASSERT_EQ(1U, main_entry->root_node()->children.size());
scoped_refptr<FrameNavigationEntry> frame_entry =
main_entry->root_node()->children[0]->frame_entry.get();
EXPECT_EQ(frame_entry->redirect_chain().size(), 2u);
EXPECT_EQ(frame_entry->redirect_chain()[0], iframe_redirect_url);
EXPECT_EQ(frame_entry->redirect_chain()[1], iframe_final_url);
ExpectReferrerWithDefaultPolicy(main_entry, GURL());
ExpectReferrerWithDefaultPolicy(frame_entry.get(), main_url);
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FrameNavigationEntry_NewSubFrameRedirectChain) {
NavigationControllerImpl& controller = contents()->GetController();
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_data_iframe.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
EXPECT_EQ(1, controller.GetEntryCount());
GURL frame_final_url(embedded_test_server()->GetURL("/simple_page.html"));
GURL frame_redirect_url(
embedded_test_server()->GetURL("/server-redirect?/simple_page.html"));
NavigateFrameToURL(root->child_at(0), frame_redirect_url);
EXPECT_EQ(2, controller.GetEntryCount());
NavigationEntryImpl* main_entry = controller.GetLastCommittedEntry();
EXPECT_EQ(main_entry->GetRedirectChain().size(), 1u);
EXPECT_EQ(main_entry->GetRedirectChain()[0], main_url);
ASSERT_EQ(1U, main_entry->root_node()->children.size());
scoped_refptr<FrameNavigationEntry> frame_entry =
main_entry->root_node()->children[0]->frame_entry.get();
EXPECT_EQ(frame_entry->redirect_chain().size(), 2u);
EXPECT_EQ(frame_entry->redirect_chain()[0], frame_redirect_url);
EXPECT_EQ(frame_entry->redirect_chain()[1], frame_final_url);
ExpectReferrerWithDefaultPolicy(main_entry, GURL());
ExpectReferrerWithDefaultPolicy(frame_entry.get(), GURL());
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
FrameNavigationEntry_MainFrameRedirectChain_NormalThenSameDocNavigations) {
NavigationControllerImpl& controller = contents()->GetController();
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
{
EXPECT_TRUE(NavigateToURL(shell(), start_url));
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
ASSERT_EQ(start_url, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 1u);
EXPECT_EQ(entry->GetRedirectChain()[0], start_url);
EXPECT_FALSE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(entry->GetOriginalRequestURL(), start_url);
ExpectReferrerWithDefaultPolicy(entry, GURL());
}
GURL fragment_url(embedded_test_server()->GetURL("/title1.html#foo"));
{
TestNavigationManager navigation_manager(contents(), fragment_url);
EXPECT_TRUE(ExecJs(contents(), "location.replace('#foo')"));
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(fragment_url, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 2u);
EXPECT_EQ(entry->GetRedirectChain()[0], start_url);
EXPECT_EQ(entry->GetRedirectChain()[1], fragment_url);
EXPECT_TRUE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(entry->GetOriginalRequestURL(), start_url);
ExpectReferrerWithDefaultPolicy(entry, GURL());
}
{
GURL replace_state_url(embedded_test_server()->GetURL("/title1.html#bar"));
TestNavigationManager navigation_manager(contents(), replace_state_url);
EXPECT_TRUE(
ExecJs(shell(), "history.replaceState({}, '', '/title1.html#bar')"));
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(replace_state_url, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 2u);
EXPECT_EQ(entry->GetRedirectChain()[0], fragment_url);
EXPECT_EQ(entry->GetRedirectChain()[1], replace_state_url);
EXPECT_TRUE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(entry->GetOriginalRequestURL(), start_url);
ExpectReferrerWithDefaultPolicy(entry, GURL());
}
{
GURL fragment_url_2(embedded_test_server()->GetURL("/title1.html#baz"));
EXPECT_TRUE(NavigateToURL(shell(), fragment_url_2));
EXPECT_EQ(2, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(fragment_url_2, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 1u);
EXPECT_EQ(entry->GetRedirectChain()[0], fragment_url_2);
EXPECT_TRUE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(entry->GetOriginalRequestURL(), fragment_url_2);
ExpectReferrerWithDefaultPolicy(entry, GURL());
}
{
GURL fragment_url_3(embedded_test_server()->GetURL("/title1.html#click"));
TestNavigationManager navigation_manager(contents(), fragment_url_3);
EXPECT_TRUE(ExecJs(contents(),
"let a = document.createElement('a');"
"a.href = 'title1.html#click';"
"document.body.appendChild(a);"
"a.click();"));
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_EQ(3, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(fragment_url_3, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 1u);
EXPECT_EQ(entry->GetRedirectChain()[0], fragment_url_3);
EXPECT_TRUE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(entry->GetOriginalRequestURL(), fragment_url_3);
ExpectReferrerWithDefaultPolicy(entry, GURL());
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
FrameNavigationEntry_SubframeRedirectChain_MainFrameNavigatingSubframe) {
NavigationControllerImpl& controller = contents()->GetController();
GURL start_url(embedded_test_server()->GetURL("/page_with_iframe.html"));
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
FrameTreeNode* iframe = nullptr;
GURL iframe_url;
{
EXPECT_TRUE(NavigateToURL(shell(), start_url));
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
ASSERT_EQ(start_url, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 1u);
EXPECT_EQ(entry->GetRedirectChain()[0], start_url);
EXPECT_FALSE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(entry->GetOriginalRequestURL(), start_url);
iframe = root->child_at(0);
iframe_url = iframe->current_url();
scoped_refptr<FrameNavigationEntry> frame_entry =
controller.GetLastCommittedEntry()->GetFrameEntry(iframe);
EXPECT_EQ(frame_entry->redirect_chain().size(), 1u);
EXPECT_EQ(frame_entry->redirect_chain()[0], iframe_url);
ExpectReferrerWithDefaultPolicy(frame_entry.get(), start_url);
}
GURL fragment_url(embedded_test_server()->GetURL("/title1.html#foo"));
{
TestNavigationManager navigation_manager(contents(), fragment_url);
EXPECT_TRUE(ExecJs(
contents(), JsReplace("document.getElementById('test_iframe').src = $1",
fragment_url)));
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_EQ(2, controller.GetEntryCount());
scoped_refptr<FrameNavigationEntry> frame_entry =
controller.GetLastCommittedEntry()->GetFrameEntry(iframe);
EXPECT_EQ(fragment_url, frame_entry->url());
EXPECT_EQ(frame_entry->redirect_chain().size(), 1u);
EXPECT_EQ(frame_entry->redirect_chain()[0], fragment_url);
ExpectReferrerWithDefaultPolicy(frame_entry.get(), start_url);
}
GURL fragment_url_2(embedded_test_server()->GetURL("/title1.html#bar"));
{
TestNavigationManager navigation_manager(contents(), fragment_url_2);
EXPECT_TRUE(ExecJs(contents(),
"let a = document.createElement('a');"
"a.href = 'title1.html#bar';"
"a.target = 'test_iframe';"
"document.body.appendChild(a);"
"a.click();"));
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_EQ(3, controller.GetEntryCount());
scoped_refptr<FrameNavigationEntry> frame_entry =
controller.GetLastCommittedEntry()->GetFrameEntry(iframe);
EXPECT_EQ(fragment_url_2, frame_entry->url());
EXPECT_EQ(frame_entry->redirect_chain().size(), 1u);
EXPECT_EQ(frame_entry->redirect_chain()[0], fragment_url_2);
ExpectReferrerWithDefaultPolicy(frame_entry.get(), start_url);
}
GURL cross_document_url(embedded_test_server()->GetURL("/title2.html"));
{
TestNavigationManager navigation_manager(contents(), cross_document_url);
EXPECT_TRUE(ExecJs(contents(),
"let a = document.createElement('a');"
"a.href = 'title2.html';"
"a.target = 'test_iframe';"
"document.body.appendChild(a);"
"a.click();"));
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_EQ(4, controller.GetEntryCount());
scoped_refptr<FrameNavigationEntry> frame_entry =
controller.GetLastCommittedEntry()->GetFrameEntry(iframe);
EXPECT_EQ(cross_document_url, frame_entry->url());
EXPECT_EQ(frame_entry->redirect_chain().size(), 1u);
EXPECT_EQ(frame_entry->redirect_chain()[0], cross_document_url);
ExpectReferrerWithDefaultPolicy(frame_entry.get(), start_url);
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
FrameNavigationEntry_MainFrameRedirectChain_NormalThenSameSiteNavigations) {
NavigationControllerImpl& controller = contents()->GetController();
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
{
EXPECT_TRUE(NavigateToURL(shell(), start_url));
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
ASSERT_EQ(start_url, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 1u);
EXPECT_EQ(entry->GetRedirectChain()[0], start_url);
EXPECT_FALSE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(entry->GetOriginalRequestURL(), start_url);
ExpectReferrerWithDefaultPolicy(entry, GURL());
}
GURL url_2(embedded_test_server()->GetURL("/title2.html"));
{
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
TestNavigationObserver navigation_observer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, JsReplace("location.replace($1)", url_2)));
navigation_observer.WaitForNavigationFinished();
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(url_2, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 2u);
EXPECT_EQ(entry->GetRedirectChain()[0], start_url);
EXPECT_EQ(entry->GetRedirectChain()[1], url_2);
EXPECT_TRUE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(entry->GetOriginalRequestURL(), entry->GetRedirectChain()[0]);
ExpectReferrerWithDefaultPolicy(entry, start_url);
}
{
GURL url_3(embedded_test_server()->GetURL("/title3.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_3));
EXPECT_EQ(2, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(url_3, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 1u);
EXPECT_EQ(entry->GetRedirectChain()[0], url_3);
EXPECT_FALSE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(entry->GetOriginalRequestURL(), url_3);
ExpectReferrerWithDefaultPolicy(entry, GURL());
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
FrameNavigationEntry_MainFrameRedirectChain_NormalThenCrossSiteNavigations) {
NavigationControllerImpl& controller = contents()->GetController();
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
{
EXPECT_TRUE(NavigateToURL(shell(), start_url));
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
ASSERT_EQ(start_url, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 1u);
EXPECT_EQ(entry->GetRedirectChain()[0], start_url);
EXPECT_FALSE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(entry->GetOriginalRequestURL(), start_url);
ExpectReferrerWithDefaultPolicy(entry, GURL());
}
GURL url_2(embedded_test_server()->GetURL("b.com", "/title2.html"));
{
TestNavigationObserver nav_observer(shell()->web_contents());
EXPECT_TRUE(ExecJs(shell(), JsReplace("location.replace($1)", url_2)));
nav_observer.Wait();
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(url_2, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 2u);
EXPECT_EQ(entry->GetRedirectChain()[0], start_url);
EXPECT_EQ(entry->GetRedirectChain()[1], url_2);
EXPECT_TRUE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(entry->GetOriginalRequestURL(), start_url);
ExpectReferrerWithDefaultPolicy(entry, start_url);
}
GURL url_3(embedded_test_server()->GetURL("c.com", "/title3.html"));
{
TestNavigationManager navigation_manager(contents(), url_3);
EXPECT_TRUE(
ExecJs(contents(), JsReplace("let a = document.createElement('a');"
"a.href = $1;"
"document.body.appendChild(a);"
"a.click();",
url_3)));
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_EQ(2, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(url_3, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 1u);
EXPECT_EQ(entry->GetRedirectChain()[0], url_3);
EXPECT_EQ(entry->GetOriginalRequestURL(), url_3);
ExpectReferrerWithDefaultPolicy(entry, url_2.DeprecatedGetOriginAsURL());
}
{
GURL url_4(embedded_test_server()->GetURL("d.com", "/empty.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_4));
EXPECT_EQ(3, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(url_4, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 1u);
EXPECT_EQ(entry->GetRedirectChain()[0], url_4);
EXPECT_FALSE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(entry->GetOriginalRequestURL(), url_4);
ExpectReferrerWithDefaultPolicy(entry, GURL());
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
FrameNavigationEntry_MainFrameRedirectChain_CrossOriginClientRedirect_LocationReplace) {
NavigationControllerImpl& controller = contents()->GetController();
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
EXPECT_EQ(1, controller.GetEntryCount());
GURL target_url(embedded_test_server()->GetURL("b.com", "/simple_page.html"));
TestNavigationManager navigation_manager(contents(), target_url);
EXPECT_TRUE(
ExecJs(contents(), JsReplace("location.replace($1);", target_url)));
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(entry->GetRedirectChain().size(), 2u);
EXPECT_EQ(entry->GetRedirectChain()[0], start_url);
EXPECT_EQ(entry->GetRedirectChain()[1], target_url);
EXPECT_EQ(entry->GetOriginalRequestURL(), start_url);
ExpectReferrerWithDefaultPolicy(entry, start_url);
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
FrameNavigationEntry_MainFrameRedirectChain_SameOriginThenCrossOriginRedirect_LocationReplace) {
NavigationControllerImpl& controller = contents()->GetController();
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
EXPECT_EQ(1, controller.GetEntryCount());
GURL final_url(embedded_test_server()->GetURL("b.com", "/simple_page.html"));
GURL redirecting_url(
embedded_test_server()->GetURL("/server-redirect?" + final_url.spec()));
TestNavigationManager navigation_manager(contents(), redirecting_url);
EXPECT_TRUE(
ExecJs(contents(), JsReplace("location.replace($1);", redirecting_url)));
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(entry->GetRedirectChain().size(), 3u);
EXPECT_EQ(entry->GetRedirectChain()[0], start_url);
EXPECT_EQ(entry->GetRedirectChain()[1], redirecting_url);
EXPECT_EQ(entry->GetRedirectChain()[2], final_url);
EXPECT_EQ(entry->GetOriginalRequestURL(), start_url);
ExpectReferrerWithDefaultPolicy(entry, start_url);
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
FrameNavigationEntry_MainFrameRedirectChain_SameOriginThenCrossOriginRedirect_LinkClick) {
NavigationControllerImpl& controller = contents()->GetController();
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
EXPECT_EQ(1, controller.GetEntryCount());
GURL final_url(embedded_test_server()->GetURL("b.com", "/simple_page.html"));
GURL redirecting_url(
embedded_test_server()->GetURL("/server-redirect?" + final_url.spec()));
TestNavigationManager navigation_manager(contents(), redirecting_url);
EXPECT_TRUE(
ExecJs(contents(), JsReplace("let a = document.createElement('a');"
"a.href = $1;"
"document.body.appendChild(a);"
"a.click();",
redirecting_url)));
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_EQ(2, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(entry->GetRedirectChain().size(), 2u);
EXPECT_EQ(entry->GetRedirectChain()[0], redirecting_url);
EXPECT_EQ(entry->GetRedirectChain()[1], final_url);
EXPECT_EQ(entry->GetOriginalRequestURL(), redirecting_url);
ExpectReferrerWithDefaultPolicy(entry, start_url.DeprecatedGetOriginAsURL());
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
FrameNavigationEntry_MainFrameRedirectChain_CrossOriginThenSameOriginRedirect_LinkClick) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
EXPECT_EQ(1, controller.GetEntryCount());
GURL final_url(embedded_test_server()->GetURL("/simple_page.html"));
GURL redirecting_url(embedded_test_server()->GetURL(
"b.com", "/server-redirect?" + final_url.spec()));
TestNavigationManager navigation_manager(shell()->web_contents(),
redirecting_url);
EXPECT_TRUE(
ExecJs(contents(), JsReplace("let a = document.createElement('a');"
"a.href = $1;"
"document.body.appendChild(a);"
"a.click();",
redirecting_url)));
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_EQ(2, controller.GetEntryCount());
content::NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(entry->GetRedirectChain().size(), 2u);
EXPECT_EQ(entry->GetRedirectChain()[0], redirecting_url);
EXPECT_EQ(entry->GetRedirectChain()[1], final_url);
EXPECT_EQ(entry->GetOriginalRequestURL(), redirecting_url);
ExpectReferrerWithDefaultPolicy(entry, start_url.DeprecatedGetOriginAsURL());
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
FrameNavigationEntry_MainFrameRedirectChain_NormalThenReloads) {
NavigationControllerImpl& controller = contents()->GetController();
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
{
EXPECT_TRUE(NavigateToURL(shell(), start_url));
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
ASSERT_EQ(start_url, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 1u);
EXPECT_EQ(entry->GetRedirectChain()[0], start_url);
EXPECT_FALSE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(entry->GetOriginalRequestURL(), start_url);
ExpectReferrerWithDefaultPolicy(entry, GURL());
}
{
TestNavigationManager navigation_manager(contents(), start_url);
shell()->Reload();
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(start_url, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 1u);
EXPECT_EQ(entry->GetRedirectChain()[0], start_url);
EXPECT_FALSE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(entry->GetOriginalRequestURL(), start_url);
ExpectReferrerWithDefaultPolicy(entry, GURL());
}
{
TestNavigationManager navigation_manager(contents(), start_url);
EXPECT_TRUE(ExecJs(contents(), "location.reload();"));
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(start_url, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 2u);
EXPECT_EQ(entry->GetRedirectChain()[0], start_url);
EXPECT_EQ(entry->GetRedirectChain()[1], start_url);
ASSERT_TRUE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(start_url, entry->GetReplacedEntryData()->first_committed_url);
EXPECT_EQ(entry->GetOriginalRequestURL(), start_url);
ExpectReferrerWithDefaultPolicy(entry, start_url);
}
{
TestNavigationManager navigation_manager(contents(), start_url);
shell()->Reload();
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(start_url, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 1u);
EXPECT_EQ(entry->GetRedirectChain()[0], start_url);
ASSERT_TRUE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(start_url, entry->GetReplacedEntryData()->first_committed_url);
EXPECT_EQ(entry->GetOriginalRequestURL(), start_url);
ExpectReferrerWithDefaultPolicy(entry, start_url);
}
{
TestNavigationManager navigation_manager(contents(), start_url);
contents()->GetPrimaryMainFrame()->Reload();
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(start_url, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 1u);
EXPECT_EQ(entry->GetRedirectChain()[0], start_url);
ASSERT_TRUE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(start_url, entry->GetReplacedEntryData()->first_committed_url);
EXPECT_EQ(entry->GetOriginalRequestURL(), start_url);
ExpectReferrerWithDefaultPolicy(entry, start_url);
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
FrameNavigationEntry_MainFrameRedirectChain_NormalThenReloads_Subframe) {
NavigationControllerImpl& controller = contents()->GetController();
GURL start_url(embedded_test_server()->GetURL("/page_with_iframe.html"));
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
FrameTreeNode* iframe = nullptr;
GURL iframe_url;
{
EXPECT_TRUE(NavigateToURL(shell(), start_url));
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
ASSERT_EQ(start_url, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 1u);
EXPECT_EQ(entry->GetRedirectChain()[0], start_url);
EXPECT_FALSE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(entry->GetOriginalRequestURL(), start_url);
iframe = root->child_at(0);
iframe_url = iframe->current_url();
scoped_refptr<FrameNavigationEntry> frame_entry =
controller.GetLastCommittedEntry()->GetFrameEntry(iframe);
EXPECT_EQ(frame_entry->redirect_chain().size(), 1u);
EXPECT_EQ(frame_entry->redirect_chain()[0], iframe_url);
ExpectReferrerWithDefaultPolicy(frame_entry.get(), start_url);
}
{
TestNavigationManager navigation_manager(contents(), iframe_url);
root->child_at(0)->current_frame_host()->Reload();
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_EQ(1, controller.GetEntryCount());
scoped_refptr<FrameNavigationEntry> frame_entry =
controller.GetLastCommittedEntry()->GetFrameEntry(iframe);
EXPECT_EQ(iframe_url, frame_entry->url());
EXPECT_EQ(frame_entry->redirect_chain().size(), 2u);
EXPECT_EQ(frame_entry->redirect_chain()[0], iframe_url);
EXPECT_EQ(frame_entry->redirect_chain()[1], iframe_url);
ExpectReferrerWithDefaultPolicy(frame_entry.get(), start_url);
}
{
TestNavigationManager navigation_manager(contents(), iframe_url);
EXPECT_TRUE(ExecJs(iframe, "location.reload();"));
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_EQ(1, controller.GetEntryCount());
scoped_refptr<FrameNavigationEntry> frame_entry =
controller.GetLastCommittedEntry()->GetFrameEntry(iframe);
EXPECT_EQ(iframe_url, frame_entry->url());
EXPECT_EQ(frame_entry->redirect_chain().size(), 2u);
EXPECT_EQ(frame_entry->redirect_chain()[0], iframe_url);
EXPECT_EQ(frame_entry->redirect_chain()[1], iframe_url);
ExpectReferrerWithDefaultPolicy(frame_entry.get(), iframe_url);
}
{
TestNavigationManager navigation_manager(contents(), iframe_url);
root->child_at(0)->current_frame_host()->Reload();
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_EQ(1, controller.GetEntryCount());
scoped_refptr<FrameNavigationEntry> frame_entry =
controller.GetLastCommittedEntry()->GetFrameEntry(iframe);
EXPECT_EQ(iframe_url, frame_entry->url());
EXPECT_EQ(frame_entry->redirect_chain().size(), 3u);
EXPECT_EQ(frame_entry->redirect_chain()[0], iframe_url);
EXPECT_EQ(frame_entry->redirect_chain()[1], iframe_url);
EXPECT_EQ(frame_entry->redirect_chain()[2], iframe_url);
ExpectReferrerWithDefaultPolicy(frame_entry.get(), iframe_url);
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
FrameNavigationEntry_MainFrameRedirectChain_NormalThenErrorPage) {
NavigationControllerImpl& controller = contents()->GetController();
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
{
EXPECT_TRUE(NavigateToURL(shell(), start_url));
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
ASSERT_EQ(start_url, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 1u);
EXPECT_EQ(entry->GetRedirectChain()[0], start_url);
EXPECT_FALSE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(entry->GetOriginalRequestURL(), start_url);
ExpectReferrerWithDefaultPolicy(entry, GURL());
}
GURL url_2(embedded_test_server()->GetURL("b.com", "/empty404.html"));
{
EXPECT_FALSE(NavigateToURLFromRenderer(shell(), url_2));
EXPECT_EQ(2, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(url_2, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 1u);
EXPECT_EQ(entry->GetRedirectChain()[0], url_2);
EXPECT_FALSE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(entry->GetOriginalRequestURL(), url_2);
ExpectReferrerWithDefaultPolicy(entry,
start_url.DeprecatedGetOriginAsURL());
}
{
GURL url_3(embedded_test_server()->GetURL("c.com", "/empty404.html"));
EXPECT_FALSE(NavigateToURL(shell(), url_3));
EXPECT_EQ(3, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(url_3, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 1u);
EXPECT_EQ(entry->GetRedirectChain()[0], url_3);
EXPECT_FALSE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(entry->GetOriginalRequestURL(), url_3);
ExpectReferrerWithDefaultPolicy(entry, GURL());
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
FrameNavigationEntry_ServerRedirectToErrorPage_BrowserInitiated) {
NavigationControllerImpl& controller = contents()->GetController();
GURL server_redirecting_url(
embedded_test_server()->GetURL("/server-redirect?/empty404.html"));
EXPECT_FALSE(NavigateToURL(shell(), server_redirecting_url));
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
GURL fail_url(embedded_test_server()->GetURL("/empty404.html"));
EXPECT_EQ(fail_url, entry->GetURL());
EXPECT_THAT(entry->GetRedirectChain(),
testing::ElementsAre(server_redirecting_url, fail_url));
EXPECT_FALSE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(entry->GetOriginalRequestURL(), server_redirecting_url);
ExpectReferrerWithDefaultPolicy(entry, GURL());
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
FrameNavigationEntry_ServerRedirectToErrorPage_RendererInitiated) {
NavigationControllerImpl& controller = contents()->GetController();
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
{
EXPECT_TRUE(NavigateToURL(shell(), start_url));
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
ASSERT_EQ(start_url, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 1u);
EXPECT_EQ(entry->GetRedirectChain()[0], start_url);
EXPECT_FALSE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(entry->GetOriginalRequestURL(), start_url);
ExpectReferrerWithDefaultPolicy(entry, GURL());
}
{
GURL server_redirecting_url(
embedded_test_server()->GetURL("/server-redirect?/empty404.html"));
GURL fail_url(embedded_test_server()->GetURL("/empty404.html"));
EXPECT_FALSE(NavigateToURLFromRenderer(shell(), server_redirecting_url));
EXPECT_EQ(2, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(fail_url, entry->GetURL());
EXPECT_THAT(entry->GetRedirectChain(),
testing::ElementsAre(server_redirecting_url, fail_url));
EXPECT_FALSE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(entry->GetOriginalRequestURL(), server_redirecting_url);
ExpectReferrerWithDefaultPolicy(entry, start_url);
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
ServerRedirectToSameURLErrorPage) {
NavigationControllerImpl& controller = contents()->GetController();
GURL fail_url(embedded_test_server()->GetURL("/empty404.html"));
GURL server_redirecting_url(
embedded_test_server()->GetURL("/server-redirect?/empty404.html"));
EXPECT_FALSE(NavigateToURL(shell(), fail_url));
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntry* last_entry = controller.GetLastCommittedEntry();
EXPECT_EQ(fail_url, last_entry->GetURL());
EXPECT_FALSE(NavigateToURL(shell(), server_redirecting_url, fail_url));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_NE(last_entry, controller.GetLastCommittedEntry());
last_entry = controller.GetLastCommittedEntry();
EXPECT_EQ(fail_url, last_entry->GetURL());
EXPECT_TRUE(last_entry->GetReplacedEntryData().has_value());
EXPECT_EQ(fail_url, last_entry->GetReplacedEntryData()->first_committed_url);
ExpectReferrerWithDefaultPolicy(last_entry, GURL());
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
FrameNavigationEntry_MainFrameRedirectChain_ClientRedirectThenFragment) {
NavigationControllerImpl& controller = contents()->GetController();
GURL client_redirecting_url(embedded_test_server()->GetURL(
"/navigation_controller/client_redirect.html"));
GURL client_redirect_target_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
{
TestNavigationManager navigation_manager_1(contents(),
client_redirecting_url);
TestNavigationManager navigation_manager_2(contents(),
client_redirect_target_url);
shell()->LoadURL(client_redirecting_url);
ASSERT_TRUE(navigation_manager_1
.WaitForNavigationFinished());
ASSERT_TRUE(navigation_manager_2
.WaitForNavigationFinished());
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetEntryAtIndex(0);
ASSERT_EQ(client_redirect_target_url, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 2u);
EXPECT_EQ(entry->GetRedirectChain()[0], client_redirecting_url);
EXPECT_EQ(entry->GetRedirectChain()[1], client_redirect_target_url);
ASSERT_TRUE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(client_redirecting_url,
entry->GetReplacedEntryData()->first_committed_url);
EXPECT_EQ(entry->GetOriginalRequestURL(), client_redirecting_url);
ExpectReferrerWithDefaultPolicy(entry, client_redirecting_url);
}
{
GURL fragment_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html#foo"));
TestNavigationManager navigation_manager(contents(), fragment_url);
EXPECT_TRUE(ExecJs(contents(), "location.replace('#foo');"));
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(fragment_url, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 2u);
EXPECT_EQ(entry->GetRedirectChain()[0], client_redirect_target_url);
EXPECT_EQ(entry->GetRedirectChain()[1], fragment_url);
EXPECT_TRUE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(client_redirecting_url,
entry->GetReplacedEntryData()->first_committed_url);
EXPECT_EQ(entry->GetOriginalRequestURL(), client_redirecting_url);
ExpectReferrerWithDefaultPolicy(entry, client_redirecting_url);
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
FrameNavigationEntry_MainFrameRedirectChain_ClientRedirectSameDocThenFragment) {
NavigationControllerImpl& controller = contents()->GetController();
GURL client_redirecting_url(embedded_test_server()->GetURL(
"/navigation_controller/client_redirect_fragment.html"));
GURL client_redirect_target_url(embedded_test_server()->GetURL(
"/navigation_controller/client_redirect_fragment.html#foo"));
{
TestNavigationManager navigation_manager_1(contents(),
client_redirecting_url);
TestNavigationManager navigation_manager_2(contents(),
client_redirect_target_url);
shell()->LoadURL(client_redirecting_url);
ASSERT_TRUE(navigation_manager_1
.WaitForNavigationFinished());
ASSERT_TRUE(navigation_manager_2
.WaitForNavigationFinished());
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetEntryAtIndex(0);
ASSERT_EQ(client_redirect_target_url, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 2u);
EXPECT_EQ(entry->GetRedirectChain()[0], client_redirecting_url);
EXPECT_EQ(entry->GetRedirectChain()[1], client_redirect_target_url);
ASSERT_TRUE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(client_redirecting_url,
entry->GetReplacedEntryData()->first_committed_url);
EXPECT_EQ(entry->GetOriginalRequestURL(), client_redirecting_url);
ExpectReferrerWithDefaultPolicy(entry, GURL());
}
{
GURL fragment_url(embedded_test_server()->GetURL(
"/navigation_controller/client_redirect_fragment.html#bar"));
TestNavigationManager navigation_manager(contents(), fragment_url);
EXPECT_TRUE(ExecJs(contents(), "location.replace('#bar');"));
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(fragment_url, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 2u);
EXPECT_EQ(entry->GetRedirectChain()[0], client_redirect_target_url);
EXPECT_EQ(entry->GetRedirectChain()[1], fragment_url);
EXPECT_TRUE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(client_redirecting_url,
entry->GetReplacedEntryData()->first_committed_url);
EXPECT_EQ(entry->GetOriginalRequestURL(), client_redirecting_url);
ExpectReferrerWithDefaultPolicy(entry, GURL());
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
FrameNavigationEntry_MainFrameRedirectChain_ServerThenClientRedirect) {
NavigationControllerImpl& controller = contents()->GetController();
GURL server_redirecting_url(embedded_test_server()->GetURL(
"/server-redirect?/navigation_controller/client_redirect.html"));
GURL client_redirecting_url(embedded_test_server()->GetURL(
"/navigation_controller/client_redirect.html"));
GURL final_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
{
TestNavigationManager navigation_manager_1(contents(),
server_redirecting_url);
TestNavigationManager navigation_manager_2(contents(), final_url);
shell()->LoadURL(server_redirecting_url);
ASSERT_TRUE(navigation_manager_1
.WaitForNavigationFinished());
ASSERT_TRUE(navigation_manager_2
.WaitForNavigationFinished());
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetEntryAtIndex(0);
ASSERT_EQ(final_url, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 2u);
EXPECT_EQ(entry->GetRedirectChain()[0], client_redirecting_url);
EXPECT_EQ(entry->GetRedirectChain()[1], final_url);
ASSERT_TRUE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(client_redirecting_url,
entry->GetReplacedEntryData()->first_committed_url);
EXPECT_EQ(entry->GetOriginalRequestURL(), client_redirecting_url);
ExpectReferrerWithDefaultPolicy(entry, client_redirecting_url);
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
FrameNavigationEntry_MainFrameRedirectChain_ClientThenServerRedirect) {
NavigationControllerImpl& controller = contents()->GetController();
GURL client_redirecting_url(embedded_test_server()->GetURL(
"/navigation_controller/client_redirect_server.html"));
GURL server_redirecting_url(embedded_test_server()->GetURL(
"/server-redirect?/navigation_controller/simple_page_1.html"));
GURL final_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
{
TestNavigationManager navigation_manager_1(contents(),
client_redirecting_url);
TestNavigationManager navigation_manager_2(contents(),
server_redirecting_url);
shell()->LoadURL(client_redirecting_url);
ASSERT_TRUE(navigation_manager_1
.WaitForNavigationFinished());
ASSERT_TRUE(navigation_manager_2
.WaitForNavigationFinished());
ASSERT_EQ(1, controller.GetEntryCount());
NavigationEntry* entry = controller.GetEntryAtIndex(0);
ASSERT_EQ(final_url, entry->GetURL());
EXPECT_EQ(entry->GetRedirectChain().size(), 3u);
EXPECT_EQ(entry->GetRedirectChain()[0], client_redirecting_url);
EXPECT_EQ(entry->GetRedirectChain()[1], server_redirecting_url);
EXPECT_EQ(entry->GetRedirectChain()[2], final_url);
ASSERT_TRUE(entry->GetReplacedEntryData().has_value());
EXPECT_EQ(client_redirecting_url,
entry->GetReplacedEntryData()->first_committed_url);
EXPECT_EQ(entry->GetOriginalRequestURL(), client_redirecting_url);
ExpectReferrerWithDefaultPolicy(entry, client_redirecting_url);
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
RestoreWithoutExtraOopifs) {
GURL main_url_a(embedded_test_server()->GetURL(
"a.com", "/navigation_controller/page_with_data_iframe.html"));
GURL data_url("data:text/html,Subframe");
EXPECT_TRUE(NavigateToURL(shell(), main_url_a));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(main_url_a, root->current_url());
EXPECT_EQ(data_url, root->child_at(0)->current_url());
GURL frame_url_b(embedded_test_server()->GetURL(
"b.com", "/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url_b));
EXPECT_EQ(main_url_a, root->current_url());
EXPECT_EQ(frame_url_b, root->child_at(0)->current_url());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry2 = controller.GetLastCommittedEntry();
std::unique_ptr<NavigationEntryImpl> restored_entry =
NavigationEntryImpl::FromNavigationEntry(
NavigationController::CreateNavigationEntry(
main_url_a, Referrer(), absl::nullopt ,
absl::nullopt,
ui::PAGE_TRANSITION_RELOAD, false, std::string(),
controller.GetBrowserContext(),
nullptr ));
EXPECT_EQ(0U, restored_entry->root_node()->children.size());
std::unique_ptr<NavigationEntryRestoreContextImpl> context =
std::make_unique<NavigationEntryRestoreContextImpl>();
restored_entry->SetPageState(entry2->GetPageState(), context.get());
EXPECT_FALSE(
restored_entry->root_node()->children[0]->frame_entry->site_instance());
std::vector<std::unique_ptr<NavigationEntry>> entries;
entries.push_back(std::move(restored_entry));
Shell* new_shell = Shell::CreateNewWindow(
controller.GetBrowserContext(), GURL::EmptyGURL(), nullptr, gfx::Size());
FrameTreeNode* new_root =
static_cast<WebContentsImpl*>(new_shell->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& new_controller =
static_cast<NavigationControllerImpl&>(
new_shell->web_contents()->GetController());
new_controller.Restore(entries.size() - 1, RestoreType::kRestored, &entries);
ASSERT_EQ(0u, entries.size());
{
TestNavigationObserver restore_observer(new_shell->web_contents());
new_controller.LoadIfNecessary();
restore_observer.Wait();
}
ASSERT_EQ(1U, new_root->child_count());
EXPECT_EQ(main_url_a, new_root->current_url());
EXPECT_EQ(frame_url_b, new_root->child_at(0)->current_url());
if (AreStrictSiteInstancesEnabled()) {
EXPECT_NE(new_root->current_frame_host()->GetSiteInstance(),
new_root->child_at(0)->current_frame_host()->GetSiteInstance());
} else {
EXPECT_TRUE(new_root->current_frame_host()
->GetSiteInstance()
->IsDefaultSiteInstance());
EXPECT_EQ(new_root->current_frame_host()->GetSiteInstance(),
new_root->child_at(0)->current_frame_host()->GetSiteInstance());
}
}
namespace {
void DoReplaceStateWhilePending(Shell* shell,
const GURL& start_url,
const GURL& stalled_url,
const std::string& replace_state_filename) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_TRUE(NavigateToURL(shell, start_url));
TestNavigationManager stalled_navigation(shell->web_contents(), stalled_url);
controller.LoadURL(stalled_url, Referrer(), ui::PAGE_TRANSITION_LINK,
std::string());
EXPECT_TRUE(stalled_navigation.WaitForRequestStart());
NavigationEntryImpl* entry = controller.GetPendingEntry();
ASSERT_NE(nullptr, entry);
EXPECT_EQ(stalled_url, entry->GetURL());
{
FrameNavigateParamsCapturer capturer(root);
capturer.set_wait_for_load(false);
std::string script =
"history.replaceState({}, '', '" + replace_state_filename + "')";
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_TRUE(capturer.is_same_document());
}
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
NavigationTypeClassification_On1SameDocumentToXWhile2Pending) {
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
GURL url2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
DoReplaceStateWhilePending(shell(), url1, url2, "x");
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
NavigationTypeClassification_On1SameDocumentTo2While2Pending) {
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
GURL url2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
DoReplaceStateWhilePending(shell(), url1, url2, "simple_page_2.html");
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
NavigationTypeClassification_On1SameDocumentToXWhile1Pending) {
GURL url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
DoReplaceStateWhilePending(shell(), url, url, "x");
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
NavigationTypeClassification_On1SameDocumentTo1While1Pending) {
GURL url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
DoReplaceStateWhilePending(shell(), url, url, "simple_page_1.html");
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
OtherCommitDuringPendingEntryWithReplacement) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL start_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
int entry_count = controller.GetEntryCount();
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(start_url, controller.GetLastCommittedEntry()->GetURL());
GURL foo_url(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/page_with_links.html"));
TestNavigationManager stalled_navigation(shell()->web_contents(), foo_url);
NavigationController::LoadURLParams params(foo_url);
params.should_replace_current_entry = true;
controller.LoadURLWithParams(params);
EXPECT_TRUE(stalled_navigation.WaitForRequestStart());
NavigationEntryImpl* entry = controller.GetPendingEntry();
ASSERT_NE(nullptr, entry);
EXPECT_EQ(foo_url, entry->GetURL());
EXPECT_EQ(entry_count, controller.GetEntryCount());
{
FrameNavigateParamsCapturer capturer(root);
capturer.set_wait_for_load(false);
std::string script = "history.pushState({}, '', 'pushed')";
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.is_same_document());
}
GURL push_state_url(
embedded_test_server()->GetURL("/navigation_controller/pushed"));
EXPECT_EQ(entry_count + 1, controller.GetEntryCount());
EXPECT_EQ(push_state_url, controller.GetLastCommittedEntry()->GetURL());
EXPECT_EQ(start_url, controller.GetEntryAtIndex(0)->GetURL());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
BackFromPageWithReplaceStateInBeforeUnload) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
controller.GetBackForwardCache().DisableForTesting(
content::BackForwardCache::TEST_USES_UNLOAD_EVENT);
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL start_url(embedded_test_server()->GetURL(
"/navigation_controller/beforeunload_replacestate_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(start_url, controller.GetLastCommittedEntry()->GetURL());
std::string script = "document.getElementById('thelink').click()";
EXPECT_TRUE(ExecJs(root, script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
TestNavigationManager manager(shell()->web_contents(), start_url);
controller.GoBack();
EXPECT_TRUE(manager.WaitForRequestStart());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
PreventSpoofFromSubframeAndReplace) {
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
GURL url2(embedded_test_server()->GetURL(
"/navigation_controller/page_with_data_iframe.html"));
EXPECT_TRUE(NavigateToURL(shell(), url2));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(1U, root->child_count());
ASSERT_NE(nullptr, root->child_at(0));
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
}
{
TestNavigationObserver back_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoBack();
back_load_observer.Wait();
}
{
TestNavigationObserver forward_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoForward();
forward_load_observer.Wait();
}
GURL url3(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe.html"));
{
TestNavigationObserver replace_load_observer(shell()->web_contents());
std::string script = "location.replace('" + url3.spec() + "')";
EXPECT_TRUE(ExecJs(root, script));
replace_load_observer.Wait();
}
{
TestNavigationObserver back_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoBack();
back_load_observer.Wait();
EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
EXPECT_EQ(url2, shell()->web_contents()->GetLastCommittedURL());
EXPECT_EQ(url2, root->current_url());
}
{
TestNavigationObserver back_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoBack();
back_load_observer.Wait();
EXPECT_EQ(url1, shell()->web_contents()->GetLastCommittedURL());
EXPECT_EQ(url1, root->current_url());
}
{
TestNavigationObserver back_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoForward();
back_load_observer.Wait();
EXPECT_EQ(url2, shell()->web_contents()->GetLastCommittedURL());
EXPECT_EQ(url2, root->current_url());
}
{
TestNavigationObserver forward_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoForward();
forward_load_observer.Wait();
EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
EXPECT_EQ(url3, shell()->web_contents()->GetLastCommittedURL());
EXPECT_EQ(url3, root->current_url());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
SubframeBackFromReplaceState) {
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/page_with_data_iframe.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(1U, root->child_count());
ASSERT_NE(nullptr, root->child_at(0));
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
}
{
FrameNavigateParamsCapturer capturer(root);
std::string script = "history.replaceState({}, 'replaced', 'replaced')";
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
}
GURL replaced_url = shell()->web_contents()->GetLastCommittedURL();
{
TestNavigationObserver back_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoBack();
back_load_observer.Wait();
}
EXPECT_EQ(replaced_url, shell()->web_contents()->GetLastCommittedURL());
EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
SubframeBackFromReplaceStateInClonedTab) {
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/page_with_data_iframe.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
NavigationControllerImpl& original_controller =
static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(1U, root->child_count());
ASSERT_NE(nullptr, root->child_at(0));
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
}
std::unique_ptr<WebContents> new_tab = shell()->web_contents()->Clone();
WebContentsImpl* cloned_tab_impl =
static_cast<WebContentsImpl*>(new_tab.get());
NavigationControllerImpl& cloned_controller =
static_cast<NavigationControllerImpl&>(cloned_tab_impl->GetController());
EXPECT_TRUE(cloned_controller.IsInitialNavigation());
EXPECT_TRUE(cloned_controller.NeedsReload());
ASSERT_EQ(2, original_controller.GetEntryCount());
ASSERT_EQ(2, cloned_controller.GetEntryCount());
NavigationEntryImpl* original_previous_entry =
original_controller.GetEntryAtIndex(0);
NavigationEntryImpl* original_current_entry =
original_controller.GetEntryAtIndex(1);
NavigationEntryImpl* cloned_previous_entry =
cloned_controller.GetEntryAtIndex(0);
NavigationEntryImpl* cloned_current_entry =
cloned_controller.GetEntryAtIndex(1);
EXPECT_NE(original_current_entry->root_node()->frame_entry.get(),
cloned_current_entry->root_node()->frame_entry.get());
EXPECT_NE(original_current_entry->root_node()->children[0]->frame_entry.get(),
cloned_current_entry->root_node()->children[0]->frame_entry.get());
EXPECT_EQ(original_previous_entry->root_node()->frame_entry.get(),
original_current_entry->root_node()->frame_entry.get());
EXPECT_EQ(cloned_previous_entry->root_node()->frame_entry.get(),
cloned_current_entry->root_node()->frame_entry.get());
{
FrameNavigateParamsCapturer capturer(root);
std::string script = "history.replaceState({}, 'replaced', 'replaced2')";
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
}
{
TestNavigationObserver back_load_observer(new_tab.get());
new_tab->GetController().GoBack();
back_load_observer.Wait();
}
FrameTreeNode* cloned_root = cloned_tab_impl->GetPrimaryFrameTree().root();
EXPECT_TRUE(cloned_root->current_frame_host()->IsRenderFrameLive());
EXPECT_EQ(original_current_entry,
original_controller.GetLastCommittedEntry());
EXPECT_EQ(cloned_previous_entry, cloned_controller.GetLastCommittedEntry());
EXPECT_EQ(cloned_previous_entry, cloned_controller.GetLastCommittedEntry());
EXPECT_NE(original_previous_entry->root_node()->frame_entry->url(),
cloned_previous_entry->root_node()->frame_entry->url());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
SubframeBackFromSubframeLocationReplace) {
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL main_url(
embedded_test_server()->GetURL("a.com", "/page_with_blank_iframe.html"));
GURL middle_frame_url(embedded_test_server()->GetURL(
"b.com", "/frame_tree/page_with_srcdoc_frame.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
ASSERT_EQ(1U, root->child_count());
FrameTreeNode* child = root->child_at(0);
{
FrameNavigateParamsCapturer capturer(child);
EXPECT_TRUE(NavigateToURLFromRenderer(child, middle_frame_url));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
}
ASSERT_EQ(1U, child->child_count());
FrameTreeNode* grandchild = child->child_at(0);
EXPECT_EQ(middle_frame_url,
child->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(GURL(url::kAboutSrcdocURL),
grandchild->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(url::Origin::Create(middle_frame_url),
grandchild->current_frame_host()->GetLastCommittedOrigin());
NavigationEntryImpl* entry1 = controller.GetLastCommittedEntry();
{
FrameNavigateParamsCapturer capturer(grandchild);
EXPECT_TRUE(ExecJs(root, "frames[0][0].location = 'about:blank';"));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
}
EXPECT_EQ(GURL(url::kAboutBlankURL),
grandchild->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(url::Origin::Create(main_url),
grandchild->current_frame_host()->GetLastCommittedOrigin());
EXPECT_EQ(2, controller.GetEntryCount());
NavigationEntryImpl* entry2 = controller.GetLastCommittedEntry();
EXPECT_NE(entry1, entry2);
EXPECT_EQ(entry1->GetFrameEntry(child), entry2->GetFrameEntry(child));
EXPECT_NE(entry1->GetFrameEntry(grandchild),
entry2->GetFrameEntry(grandchild));
{
FrameNavigateParamsCapturer capturer(child);
EXPECT_TRUE(
ExecJs(root, JsReplace("frames[0].location.replace($1)", main_url)));
capturer.Wait();
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
}
grandchild = child->child_at(0);
EXPECT_EQ(GURL(url::kAboutBlankURL),
grandchild->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(url::Origin::Create(main_url),
grandchild->current_frame_host()->GetLastCommittedOrigin());
EXPECT_NE(entry1->GetFrameEntry(child), entry2->GetFrameEntry(child));
{
TestNavigationObserver observer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, "history.back()"));
observer.Wait();
}
grandchild = child->child_at(0);
EXPECT_EQ(middle_frame_url,
child->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(GURL(url::kAboutSrcdocURL),
grandchild->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(url::Origin::Create(middle_frame_url),
grandchild->current_frame_host()->GetLastCommittedOrigin());
EXPECT_EQ(child->current_frame_host()->GetProcess(),
grandchild->current_frame_host()->GetProcess());
if (AreAllSitesIsolatedForTesting()) {
EXPECT_NE(root->current_frame_host()->GetProcess(),
grandchild->current_frame_host()->GetProcess());
}
EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
SubframeBackFromSubframeLocationReplaceAfterCrash) {
if (!AreAllSitesIsolatedForTesting()) {
return;
}
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL main_url(
embedded_test_server()->GetURL("a.com", "/page_with_blank_iframe.html"));
GURL middle_frame_url(embedded_test_server()->GetURL(
"b.com", "/frame_tree/page_with_srcdoc_frame.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
ASSERT_EQ(1U, root->child_count());
FrameTreeNode* child = root->child_at(0);
{
FrameNavigateParamsCapturer capturer(child);
EXPECT_TRUE(NavigateToURLFromRenderer(child, middle_frame_url));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
}
ASSERT_EQ(1U, child->child_count());
FrameTreeNode* grandchild = child->child_at(0);
EXPECT_EQ(middle_frame_url,
child->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(GURL(url::kAboutSrcdocURL),
grandchild->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(url::Origin::Create(middle_frame_url),
grandchild->current_frame_host()->GetLastCommittedOrigin());
NavigationEntryImpl* entry1 = controller.GetLastCommittedEntry();
{
FrameNavigateParamsCapturer capturer(grandchild);
EXPECT_TRUE(ExecJs(root, "frames[0][0].location = 'about:blank';"));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
}
EXPECT_EQ(GURL(url::kAboutBlankURL),
grandchild->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(url::Origin::Create(main_url),
grandchild->current_frame_host()->GetLastCommittedOrigin());
EXPECT_EQ(2, controller.GetEntryCount());
NavigationEntryImpl* entry2 = controller.GetLastCommittedEntry();
EXPECT_NE(entry1, entry2);
EXPECT_EQ(entry1->GetFrameEntry(child), entry2->GetFrameEntry(child));
EXPECT_NE(entry1->GetFrameEntry(grandchild),
entry2->GetFrameEntry(grandchild));
RenderProcessHost* process_b = child->current_frame_host()->GetProcess();
RenderProcessHostWatcher crash_observer(
process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
EXPECT_TRUE(process_b->Shutdown(RESULT_CODE_KILLED));
crash_observer.Wait();
{
FrameNavigateParamsCapturer capturer(child);
EXPECT_TRUE(
ExecJs(root, JsReplace("frames[0].location.replace($1)", main_url)));
capturer.Wait();
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
}
grandchild = child->child_at(0);
EXPECT_EQ(GURL(url::kAboutBlankURL),
grandchild->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(url::Origin::Create(main_url),
grandchild->current_frame_host()->GetLastCommittedOrigin());
EXPECT_NE(entry1->GetFrameEntry(child), entry2->GetFrameEntry(child));
{
TestNavigationObserver observer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, "history.back()"));
observer.Wait();
}
grandchild = child->child_at(0);
EXPECT_EQ(middle_frame_url,
child->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(GURL(url::kAboutSrcdocURL),
grandchild->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(url::Origin::Create(middle_frame_url),
grandchild->current_frame_host()->GetLastCommittedOrigin());
EXPECT_EQ(child->current_frame_host()->GetProcess(),
grandchild->current_frame_host()->GetProcess());
if (AreAllSitesIsolatedForTesting()) {
EXPECT_NE(root->current_frame_host()->GetProcess(),
grandchild->current_frame_host()->GetProcess());
}
EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
RestoreSharedFrameEntryWithOpaqueInitiator) {
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL data_url("data:text/html,<iframe></iframe>");
EXPECT_TRUE(NavigateToURL(shell(), data_url));
NavigationEntryImpl* entry1 = controller.GetLastCommittedEntry();
FrameTreeNode* child = root->child_at(0);
ASSERT_TRUE(entry1->GetFrameEntry(child)->initiator_origin()->opaque());
GURL data_url_fragment("data:text/html,<iframe></iframe>#foo");
EXPECT_TRUE(NavigateToURL(shell(), data_url_fragment));
NavigationEntryImpl* entry2 = controller.GetLastCommittedEntry();
ASSERT_EQ(entry1->GetFrameEntry(child), entry2->GetFrameEntry(child));
std::unique_ptr<NavigationEntryRestoreContextImpl> context =
std::make_unique<NavigationEntryRestoreContextImpl>();
std::unique_ptr<NavigationEntryImpl> restored_entry1 = entry1->Clone();
restored_entry1->SetPageState(entry1->GetPageState(), context.get());
std::unique_ptr<NavigationEntryImpl> restored_entry2 = entry2->Clone();
restored_entry2->SetPageState(entry2->GetPageState(), context.get());
std::vector<std::unique_ptr<NavigationEntry>> restored_entries;
restored_entries.push_back(std::move(restored_entry1));
restored_entries.push_back(std::move(restored_entry2));
Shell* new_shell = Shell::CreateNewWindow(
controller.GetBrowserContext(), GURL::EmptyGURL(), nullptr, gfx::Size());
WebContentsImpl* new_web_contents =
static_cast<WebContentsImpl*>(new_shell->web_contents());
NavigationControllerImpl& new_controller =
static_cast<NavigationControllerImpl&>(new_web_contents->GetController());
new_controller.Restore(restored_entries.size() - 1, RestoreType::kRestored,
&restored_entries);
{
TestNavigationObserver restore_observer(new_shell->web_contents());
new_controller.LoadIfNecessary();
restore_observer.Wait();
}
NavigationEntryImpl* new_entry2 = new_controller.GetEntryAtIndex(1);
EXPECT_EQ(new_entry2, new_controller.GetLastCommittedEntry());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
RestoreNonSharedFrameEntryWithCrossOriginInitiator) {
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
NavigationEntryImpl* entry1 = controller.GetLastCommittedEntry();
GURL url2(embedded_test_server()->GetURL(
"b.com", "/navigation_controller/page_with_iframe_simple.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(shell(), url2));
NavigationEntryImpl* entry2 = controller.GetLastCommittedEntry();
url::Origin initiator_origin2 =
entry2->GetFrameEntry(root)->initiator_origin().value();
ASSERT_EQ(initiator_origin2, url::Origin::Create(url1));
blink::PageState entry1_state = entry1->GetPageState();
blink::PageState entry2_state = entry2->GetPageState();
GURL frame_url(embedded_test_server()->GetURL(
"b.com", "/navigation_controller/simple_page_2.html"));
FrameTreeNode* child = root->child_at(0);
{
FrameNavigateParamsCapturer capturer(child);
ASSERT_TRUE(NavigateFrameToURL(child, frame_url));
capturer.Wait();
}
NavigationEntryImpl* entry3 = controller.GetLastCommittedEntry();
GURL url2_fragment(url2.spec() + "#foo");
{
FrameNavigateParamsCapturer capturer(root);
std::string script =
"history.replaceState({}, 'replaced', '" + url2_fragment.spec() + "')";
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
}
url::Origin initiator_origin3 =
entry3->GetFrameEntry(root)->initiator_origin().value();
ASSERT_EQ(initiator_origin3, url::Origin::Create(url2));
EXPECT_NE(initiator_origin3, initiator_origin2);
blink::PageState entry3_state = entry3->GetPageState();
std::unique_ptr<NavigationEntryRestoreContextImpl> context1 =
std::make_unique<NavigationEntryRestoreContextImpl>();
std::unique_ptr<NavigationEntryImpl> restored_entry1 = entry1->Clone();
restored_entry1->SetPageState(entry1_state, context1.get());
std::unique_ptr<NavigationEntryImpl> restored_entry2 = entry2->Clone();
restored_entry2->SetPageState(entry2_state, context1.get());
std::unique_ptr<NavigationEntryImpl> restored_entry3 = entry3->Clone();
restored_entry3->SetPageState(entry3_state, context1.get());
EXPECT_NE(restored_entry2->GetFrameEntry(root),
restored_entry3->GetFrameEntry(root));
EXPECT_NE(restored_entry2->GetFrameEntry(root)->initiator_origin().value(),
restored_entry3->GetFrameEntry(root)->initiator_origin().value());
std::vector<std::unique_ptr<NavigationEntry>> restored_entries;
restored_entries.push_back(std::move(restored_entry1));
restored_entries.push_back(std::move(restored_entry2));
restored_entries.push_back(std::move(restored_entry3));
Shell* shell2 = Shell::CreateNewWindow(
controller.GetBrowserContext(), GURL::EmptyGURL(), nullptr, gfx::Size());
WebContentsImpl* web_contents2 =
static_cast<WebContentsImpl*>(shell2->web_contents());
FrameTreeNode* root2 = static_cast<WebContentsImpl*>(shell2->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& controller2 =
static_cast<NavigationControllerImpl&>(web_contents2->GetController());
controller2.Restore(restored_entries.size() - 1, RestoreType::kRestored,
&restored_entries);
{
TestNavigationObserver restore_observer(shell2->web_contents());
controller2.LoadIfNecessary();
restore_observer.Wait();
}
NavigationEntryImpl* new_entry1 = controller2.GetEntryAtIndex(0);
NavigationEntryImpl* new_entry2 = controller2.GetEntryAtIndex(1);
NavigationEntryImpl* new_entry3 = controller2.GetEntryAtIndex(2);
EXPECT_EQ(new_entry3, controller2.GetLastCommittedEntry());
{
FrameNavigateParamsCapturer capturer(root2);
std::string script = "history.replaceState({}, '', '" + url2.spec() + "')";
EXPECT_TRUE(ExecJs(root2, script));
capturer.Wait();
}
EXPECT_NE(new_entry2->GetFrameEntry(root2), new_entry3->GetFrameEntry(root2));
EXPECT_EQ(new_entry2->GetFrameEntry(root2)->url(),
new_entry3->GetFrameEntry(root2)->url());
EXPECT_EQ(new_entry2->GetFrameEntry(root2)->item_sequence_number(),
new_entry3->GetFrameEntry(root2)->item_sequence_number());
EXPECT_NE(new_entry2->GetFrameEntry(root2)->initiator_origin().value(),
new_entry3->GetFrameEntry(root2)->initiator_origin().value());
std::unique_ptr<NavigationEntryRestoreContextImpl> context2 =
std::make_unique<NavigationEntryRestoreContextImpl>();
std::unique_ptr<NavigationEntryImpl> restored2_entry1 = new_entry1->Clone();
restored2_entry1->SetPageState(new_entry1->GetPageState(), context2.get());
std::unique_ptr<NavigationEntryImpl> restored2_entry2 = new_entry2->Clone();
restored2_entry2->SetPageState(new_entry2->GetPageState(), context2.get());
std::unique_ptr<NavigationEntryImpl> restored2_entry3 = new_entry3->Clone();
restored2_entry3->SetPageState(new_entry3->GetPageState(), context2.get());
EXPECT_EQ(restored2_entry2->GetFrameEntry(root2),
restored2_entry3->GetFrameEntry(root2));
Shell* shell3 = Shell::CreateNewWindow(
controller.GetBrowserContext(), GURL::EmptyGURL(), nullptr, gfx::Size());
WebContentsImpl* web_contents3 =
static_cast<WebContentsImpl*>(shell3->web_contents());
FrameTreeNode* root3 = static_cast<WebContentsImpl*>(shell3->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& controller3 =
static_cast<NavigationControllerImpl&>(web_contents3->GetController());
std::vector<std::unique_ptr<NavigationEntry>> restored_entries2;
restored_entries2.push_back(std::move(restored2_entry1));
restored_entries2.push_back(std::move(restored2_entry2));
restored_entries2.push_back(std::move(restored2_entry3));
controller3.Restore(restored_entries2.size() - 1, RestoreType::kRestored,
&restored_entries2);
{
TestNavigationObserver restore_observer(shell3->web_contents());
controller3.LoadIfNecessary();
restore_observer.Wait();
}
FrameNavigationEntry* root3_fne =
controller3.GetEntryAtIndex(2)->GetFrameEntry(root3);
EXPECT_EQ(root3_fne, controller3.GetEntryAtIndex(1)->GetFrameEntry(root3));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
RestoreSessionWithInvalidPageState) {
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url1(embedded_test_server()->GetURL(
"a.com", "/navigation_controller/page_with_iframe_simple.html"));
GURL original_frame_url(embedded_test_server()->GetURL(
"a.com", "/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
NavigationEntryImpl* entry1 = controller.GetLastCommittedEntry();
FrameTreeNode* child = root->child_at(0);
ASSERT_EQ(original_frame_url, entry1->GetFrameEntry(child)->url());
GURL frame_url(embedded_test_server()->GetURL(
"b.com", "/navigation_controller/simple_page_2.html"));
{
FrameNavigateParamsCapturer capturer(child);
ASSERT_TRUE(NavigateFrameToURL(child, frame_url));
capturer.Wait();
}
NavigationEntryImpl* entry2 = controller.GetLastCommittedEntry();
blink::PageState garbage = blink::PageState::CreateFromEncodedData("garbage");
blink::ExplodedPageState exploded_state;
ASSERT_FALSE(
blink::DecodePageState(garbage.ToEncodedData(), &exploded_state));
std::unique_ptr<NavigationEntryRestoreContextImpl> context1 =
std::make_unique<NavigationEntryRestoreContextImpl>();
std::unique_ptr<NavigationEntryImpl> restored_entry1 = entry1->Clone();
restored_entry1->SetPageState(garbage, context1.get());
std::unique_ptr<NavigationEntryImpl> restored_entry2 = entry2->Clone();
restored_entry2->SetPageState(garbage, context1.get());
std::vector<std::unique_ptr<NavigationEntry>> restored_entries;
restored_entries.push_back(std::move(restored_entry1));
restored_entries.push_back(std::move(restored_entry2));
Shell* shell2 = Shell::CreateNewWindow(
controller.GetBrowserContext(), GURL::EmptyGURL(), nullptr, gfx::Size());
WebContentsImpl* web_contents2 =
static_cast<WebContentsImpl*>(shell2->web_contents());
FrameTreeNode* root2 = static_cast<WebContentsImpl*>(shell2->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& controller2 =
static_cast<NavigationControllerImpl&>(web_contents2->GetController());
controller2.Restore(restored_entries.size() - 1, RestoreType::kRestored,
&restored_entries);
{
TestNavigationObserver restore_observer(shell2->web_contents());
controller2.LoadIfNecessary();
restore_observer.Wait();
}
NavigationEntryImpl* new_entry1 = controller2.GetEntryAtIndex(0);
NavigationEntryImpl* new_entry2 = controller2.GetEntryAtIndex(1);
EXPECT_EQ(new_entry2, controller2.GetLastCommittedEntry());
FrameTreeNode* child2 = root2->child_at(0);
FrameNavigationEntry* child2_fne = new_entry2->GetFrameEntry(child2);
EXPECT_EQ(original_frame_url, child2_fne->url());
EXPECT_NE(new_entry1->GetFrameEntry(root2), new_entry2->GetFrameEntry(root2));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
StateAfterSameDocumentReplacement) {
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe_simple.html"));
GURL url1_foo(url1.spec() + "#foo");
GURL url1_bar(url1.spec() + "#bar");
GURL frame_url2(embedded_test_server()->GetURL("/title2.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
EXPECT_EQ(1, controller.GetEntryCount());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(1U, root->child_count());
NavigationEntryImpl* previous_entry = controller.GetLastCommittedEntry();
scoped_refptr<FrameNavigationEntry> previous_root_entry =
previous_entry->root_node()->frame_entry.get();
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "history.pushState('foo', '', '#foo')"));
capturer.Wait();
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ(url1_foo, contents()->GetLastCommittedURL());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
EXPECT_EQ("foo", EvalJs(root, "history.state"));
EXPECT_NE(
previous_root_entry,
controller.GetLastCommittedEntry()->root_node()->frame_entry.get());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
previous_entry = controller.GetLastCommittedEntry();
previous_root_entry = previous_entry->root_node()->frame_entry.get();
}
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url2));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
EXPECT_EQ(url1_foo, contents()->GetLastCommittedURL());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetCurrentEntryIndex());
EXPECT_EQ("foo", EvalJs(root, "history.state"));
EXPECT_EQ(
previous_root_entry,
controller.GetLastCommittedEntry()->root_node()->frame_entry.get());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
previous_entry = controller.GetLastCommittedEntry();
previous_root_entry = previous_entry->root_node()->frame_entry.get();
}
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "location.replace('#bar');"));
capturer.Wait();
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_EQ(url1_bar, contents()->GetLastCommittedURL());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetCurrentEntryIndex());
NavigationEntryImpl* current_entry = controller.GetLastCommittedEntry();
EXPECT_EQ(url1_bar, current_entry->GetURL());
EXPECT_EQ(url1_bar, controller.GetEntryAtIndex(1)->GetURL());
EXPECT_NE(current_entry, controller.GetEntryAtIndex(1));
EXPECT_EQ(current_entry->GetFrameEntry(root),
controller.GetEntryAtIndex(1)->GetFrameEntry(root));
EXPECT_EQ(nullptr, EvalJs(root, "history.state"));
EXPECT_EQ(
previous_root_entry,
controller.GetLastCommittedEntry()->root_node()->frame_entry.get());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
previous_entry = controller.GetLastCommittedEntry();
previous_root_entry = previous_entry->root_node()->frame_entry.get();
}
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
controller.GoBack();
capturer.Wait();
EXPECT_EQ(url1_bar, contents()->GetLastCommittedURL());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
EXPECT_EQ(nullptr, EvalJs(root, "history.state"));
EXPECT_EQ(
previous_root_entry,
controller.GetLastCommittedEntry()->root_node()->frame_entry.get());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
previous_entry = controller.GetLastCommittedEntry();
previous_root_entry = previous_entry->root_node()->frame_entry.get();
}
{
FrameNavigateParamsCapturer capturer(root);
controller.GoBack();
capturer.Wait();
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ(url1, contents()->GetLastCommittedURL());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ(nullptr, EvalJs(root, "history.state"));
EXPECT_NE(
previous_root_entry,
controller.GetLastCommittedEntry()->root_node()->frame_entry.get());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
StateAfterCrossDocumentReplacement) {
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/page_with_data_iframe.html"));
GURL url1_foo(url1.spec() + "#foo");
GURL url2(embedded_test_server()->GetURL("/title2.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
EXPECT_EQ(1, controller.GetEntryCount());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(1U, root->child_count());
NavigationEntryImpl* previous_entry = controller.GetLastCommittedEntry();
scoped_refptr<FrameNavigationEntry> previous_root_entry =
previous_entry->root_node()->frame_entry.get();
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "history.pushState('foo', '', '#foo')"));
capturer.Wait();
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ(url1_foo, contents()->GetLastCommittedURL());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
EXPECT_EQ("foo", EvalJs(root, "history.state"));
EXPECT_NE(
previous_root_entry,
controller.GetLastCommittedEntry()->root_node()->frame_entry.get());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
previous_entry = controller.GetLastCommittedEntry();
previous_root_entry = previous_entry->root_node()->frame_entry.get();
}
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
GURL frame_url2(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url2));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
EXPECT_EQ(url1_foo, contents()->GetLastCommittedURL());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetCurrentEntryIndex());
EXPECT_EQ("foo", EvalJs(root, "history.state"));
EXPECT_EQ(
previous_root_entry,
controller.GetLastCommittedEntry()->root_node()->frame_entry.get());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
previous_entry = controller.GetLastCommittedEntry();
previous_root_entry = previous_entry->root_node()->frame_entry.get();
}
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, JsReplace("location.replace($1);", url2)));
capturer.Wait();
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_FALSE(capturer.is_same_document());
EXPECT_EQ(url2, contents()->GetLastCommittedURL());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetCurrentEntryIndex());
EXPECT_EQ(nullptr, EvalJs(root, "history.state"));
EXPECT_NE(
previous_root_entry,
controller.GetLastCommittedEntry()->root_node()->frame_entry.get());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
previous_entry = controller.GetLastCommittedEntry();
previous_root_entry = previous_entry->root_node()->frame_entry.get();
}
{
FrameNavigateParamsCapturer capturer(root);
controller.GoBack();
capturer.Wait();
EXPECT_FALSE(capturer.is_same_document());
EXPECT_EQ(url1_foo, contents()->GetLastCommittedURL());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
EXPECT_EQ("foo", EvalJs(root, "history.state"));
EXPECT_NE(
previous_root_entry,
controller.GetLastCommittedEntry()->root_node()->frame_entry.get());
EXPECT_NE(previous_entry, controller.GetLastCommittedEntry());
}
}
namespace {
class FailureWatcher : public WebContentsObserver {
public:
explicit FailureWatcher(FrameTreeNode* node)
: WebContentsObserver(
WebContents::FromRenderFrameHost(node->current_frame_host())),
frame_tree_node_id_(node->frame_tree_node_id()),
message_loop_runner_(new MessageLoopRunner) {}
void Wait() { message_loop_runner_->Run(); }
private:
void DidFailLoad(RenderFrameHost* render_frame_host,
const GURL& validated_url,
int error_code) override {
RenderFrameHostImpl* rfh =
static_cast<RenderFrameHostImpl*>(render_frame_host);
if (rfh->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_)
return;
message_loop_runner_->Quit();
}
void DidFinishNavigation(NavigationHandle* handle) override {
if (handle->HasCommitted() ||
handle->GetFrameTreeNodeId() != frame_tree_node_id_) {
return;
}
message_loop_runner_->Quit();
}
int frame_tree_node_id_;
scoped_refptr<MessageLoopRunner> message_loop_runner_;
};
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
StopCausesFailureDespiteJavaScriptURL) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL url1(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
GURL url2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
TestNavigationManager stalled_navigation(shell()->web_contents(), url2);
controller.LoadURL(url2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
EXPECT_TRUE(stalled_navigation.WaitForResponse());
NavigationEntryImpl* entry = controller.GetPendingEntry();
ASSERT_NE(nullptr, entry);
EXPECT_EQ(url2, entry->GetURL());
{
FailureWatcher watcher(root);
GURL js("javascript:(function(){})()");
controller.LoadURL(js, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
EXPECT_EQ(entry, controller.GetPendingEntry());
EXPECT_TRUE(shell()->web_contents()->IsLoading());
shell()->web_contents()->Stop();
watcher.Wait();
EXPECT_FALSE(shell()->web_contents()->IsLoading());
}
}
namespace {
class RenderProcessKilledObserver : public WebContentsObserver {
public:
explicit RenderProcessKilledObserver(WebContents* web_contents)
: WebContentsObserver(web_contents) {}
~RenderProcessKilledObserver() override {}
void PrimaryMainFrameRenderProcessGone(
base::TerminationStatus status) override {
CHECK_NE(status,
base::TerminationStatus::TERMINATION_STATUS_PROCESS_WAS_KILLED);
}
};
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, ReloadOriginalRequest) {
if (AreStrictSiteInstancesEnabled() ||
CanCrossSiteNavigationsProactivelySwapBrowsingInstances()) {
return;
}
GURL original_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), original_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
RenderProcessKilledObserver kill_observer(shell()->web_contents());
GURL redirect_url(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_1.html"));
{
std::string script = "location.replace('" + redirect_url.spec() + "');";
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(shell(), script));
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
ui::PAGE_TRANSITION_CLIENT_REDIRECT)));
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
}
{
std::string script = "history.replaceState({}, '', 'foo');";
root->render_manager()
->current_frame_host()
->ExecuteJavaScriptWithUserGestureForTests(base::UTF8ToUTF16(script),
base::NullCallback());
EXPECT_FALSE(shell()->web_contents()->IsLoading());
shell()->web_contents()->GetController().Reload(
ReloadType::ORIGINAL_REQUEST_URL, false);
EXPECT_TRUE(shell()->web_contents()->IsLoading());
EXPECT_EQ(redirect_url, shell()->web_contents()->GetLastCommittedURL());
GURL modified_url(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/foo"));
FrameNavigateParamsCapturer capturer(root);
capturer.set_wait_for_load(false);
capturer.set_navigations_remaining(2);
capturer.Wait();
EXPECT_EQ(2U, capturer.urls().size());
EXPECT_EQ(modified_url, capturer.urls()[0]);
EXPECT_EQ(original_url, capturer.urls()[1]);
EXPECT_EQ(original_url, shell()->web_contents()->GetLastCommittedURL());
}
EXPECT_TRUE(ExecJs(shell(), "console.log('Success');"));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
InitialAboutBlankInIframeIsReplaced) {
GURL original_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), original_url));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
NavigationController& controller = shell()->web_contents()->GetController();
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(1, EvalJs(shell(), "history.length"));
std::string script =
"var iframe = document.createElement('iframe');"
"iframe.id = 'frame';"
"document.body.appendChild(iframe);";
EXPECT_TRUE(ExecJs(root, script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(1, EvalJs(shell(), "history.length"));
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
ASSERT_EQ(1U, root->child_count());
FrameTreeNode* frame = root->child_at(0);
ASSERT_NE(nullptr, frame);
GURL blank_url(url::kAboutBlankURL);
EXPECT_EQ(blank_url, frame->current_url());
script = "history.pushState({}, '', 'notarealurl.html')";
EXPECT_TRUE(ExecJs(root, script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(2, EvalJs(shell(), "history.length"));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
GURL frame_url = embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_2.html");
EXPECT_TRUE(NavigateToURLFromRenderer(frame, frame_url));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(2, EvalJs(shell(), "history.length"));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(frame_url, frame->current_url());
{
TestNavigationObserver observer(shell()->web_contents(), 1);
ASSERT_TRUE(controller.CanGoBack());
controller.GoBack();
observer.Wait();
}
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(2, EvalJs(shell(), "history.length"));
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(frame_url, frame->current_url());
std::string fragment_script = "location.href = \"#foo\";";
EXPECT_TRUE(ExecJs(frame->current_frame_host(), fragment_script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(2, EvalJs(shell(), "history.length"));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
GURL frame_url_after_fragment_nav = embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_2.html#foo");
EXPECT_EQ(frame_url_after_fragment_nav, frame->current_url());
{
TestNavigationObserver observer(shell()->web_contents(), 1);
controller.GoBack();
observer.Wait();
}
EXPECT_TRUE(ExecJs(root->current_frame_host(), "true;"));
EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
EXPECT_EQ(frame_url, frame->current_url());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
BackToIframeWithContent) {
GURL links_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_links.html"));
EXPECT_TRUE(NavigateToURL(shell(), links_url));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
NavigationController& controller = shell()->web_contents()->GetController();
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(1, EvalJs(shell(), "history.length"));
GURL frame_url_1 = embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html");
std::string script = JsReplace(
"var iframe = document.createElement('iframe');"
"iframe.src = $1;"
"iframe.id = 'frame';"
"document.body.appendChild(iframe);",
frame_url_1);
EXPECT_TRUE(ExecJs(root, script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(1, EvalJs(shell(), "history.length"));
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
ASSERT_EQ(1U, root->child_count());
FrameTreeNode* frame = root->child_at(0);
ASSERT_NE(nullptr, frame);
EXPECT_EQ(frame_url_1, frame->current_url());
script = "document.getElementById('fraglink').click()";
EXPECT_TRUE(ExecJs(root, script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(2, EvalJs(shell(), "history.length"));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(frame_url_1, frame->current_url());
GURL frame_url_2 = embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_2.html");
EXPECT_TRUE(NavigateToURLFromRenderer(frame, frame_url_2));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(3, EvalJs(shell(), "history.length"));
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(frame_url_2, frame->current_url());
{
TestNavigationObserver observer(shell()->web_contents(), 1);
ASSERT_TRUE(controller.CanGoToOffset(-2));
controller.GoToOffset(-2);
observer.Wait();
}
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(3, EvalJs(shell(), "history.length"));
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(frame_url_1, frame->current_url());
std::string fragment_script = "location.href = \"#foo\";";
EXPECT_TRUE(ExecJs(frame->current_frame_host(), fragment_script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(2, EvalJs(shell(), "history.length"));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
{
TestNavigationObserver observer(shell()->web_contents(), 1);
controller.GoBack();
observer.Wait();
}
EXPECT_TRUE(ExecJs(root->current_frame_host(), "true;"));
EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
EXPECT_EQ(frame_url_1, frame->current_url());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
DISABLED_BackTwiceToIframeWithContent) {
GURL links_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_links.html"));
EXPECT_TRUE(NavigateToURL(shell(), links_url));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
NavigationController& controller = shell()->web_contents()->GetController();
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(1, EvalJs(shell(), "history.length"));
GURL frame_url_1 = embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html");
std::string script = JsReplace(
"var iframe = document.createElement('iframe');"
"iframe.src = $1;"
"iframe.id = 'frame';"
"document.body.appendChild(iframe);",
frame_url_1);
EXPECT_TRUE(ExecJs(root->current_frame_host(), script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(1, EvalJs(shell(), "history.length"));
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
ASSERT_EQ(1U, root->child_count());
FrameTreeNode* frame = root->child_at(0);
ASSERT_NE(nullptr, frame);
EXPECT_EQ(frame_url_1, frame->current_url());
GURL frame_url_2 = embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html#foo");
std::string fragment_script = "location.href = \"#foo\";";
EXPECT_TRUE(ExecJs(frame->current_frame_host(), fragment_script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(2, EvalJs(shell(), "history.length"));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(frame_url_2, frame->current_url());
std::string link_script = "document.getElementById('fraglink').click()";
EXPECT_TRUE(ExecJs(root->current_frame_host(), link_script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(3, EvalJs(shell(), "history.length"));
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(frame_url_2, frame->current_url());
GURL frame_url_3 = embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_2.html");
EXPECT_TRUE(NavigateToURLFromRenderer(frame, frame_url_3));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(4, controller.GetEntryCount());
EXPECT_EQ(4, EvalJs(shell(), "history.length"));
EXPECT_EQ(3, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(frame_url_3, frame->current_url());
{
TestNavigationObserver observer(shell()->web_contents(), 1);
ASSERT_TRUE(controller.CanGoToOffset(-2));
controller.GoToOffset(-2);
observer.Wait();
}
EXPECT_EQ(4, controller.GetEntryCount());
EXPECT_EQ(4, EvalJs(shell(), "history.length"));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(links_url, root->current_url());
EXPECT_EQ(frame_url_2, frame->current_url());
{
TestNavigationObserver observer(shell()->web_contents(), 1);
controller.GoBack();
observer.Wait();
}
EXPECT_TRUE(ExecJs(root->current_frame_host(), "true;"));
EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
EXPECT_EQ(frame_url_1, frame->current_url());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
BackAfterIframeDocumentWrite) {
GURL links_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_links.html"));
EXPECT_TRUE(NavigateToURL(shell(), links_url));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
NavigationController& controller = shell()->web_contents()->GetController();
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(1, EvalJs(shell(), "history.length"));
GURL blank_url(url::kAboutBlankURL);
std::string script =
"var iframe = document.createElement('iframe');"
"iframe.id = 'frame';"
"document.body.appendChild(iframe);";
EXPECT_TRUE(ExecJs(root->current_frame_host(), script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(1, EvalJs(shell(), "history.length"));
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
ASSERT_EQ(1U, root->child_count());
FrameTreeNode* frame = root->child_at(0);
ASSERT_NE(nullptr, frame);
EXPECT_EQ(blank_url, frame->current_url());
std::string document_write_script =
"var iframe = document.getElementById('frame');"
"iframe.contentWindow.document.write("
" \"<a id='fraglink' href='#frag'>fragment link</a>\");"
"iframe.contentWindow.document.close();";
EXPECT_TRUE(ExecJs(root->current_frame_host(), document_write_script));
GURL frame_url_2(embedded_test_server()->GetURL(
"/navigation_controller/page_with_links.html#frag"));
std::string link_script = "document.getElementById('fraglink').click()";
EXPECT_TRUE(ExecJs(frame->current_frame_host(), link_script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(2, EvalJs(shell(), "history.length"));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(frame_url_2, frame->current_url());
{
TestNavigationObserver observer(shell()->web_contents(), 1);
controller.GoBack();
observer.Wait();
}
EXPECT_TRUE(ExecJs(root->current_frame_host(), "true;"));
EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
EXPECT_EQ(blank_url, frame->current_url());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
BackAfterIframeDocumentWriteInDataURL) {
GURL data_url("data:text/html,Top level page");
EXPECT_TRUE(NavigateToURL(shell(), data_url));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
NavigationController& controller = shell()->web_contents()->GetController();
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(1, EvalJs(shell(), "history.length"));
const url::Origin opaque_origin = root->current_origin();
EXPECT_TRUE(opaque_origin.opaque());
EXPECT_EQ(url::SchemeHostPort(),
opaque_origin.GetTupleOrPrecursorTupleIfOpaque());
GURL blank_url(url::kAboutBlankURL);
std::string script =
"var iframe = document.createElement('iframe');"
"iframe.id = 'frame';"
"document.body.appendChild(iframe);";
EXPECT_TRUE(ExecJs(root, script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(1, EvalJs(root, "history.length"));
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
ASSERT_EQ(1U, root->child_count());
FrameTreeNode* frame = root->child_at(0);
ASSERT_NE(nullptr, frame);
EXPECT_EQ(blank_url, frame->current_url());
EXPECT_EQ(opaque_origin, root->current_origin());
EXPECT_EQ(opaque_origin, frame->current_origin());
std::string html = "<a id='fraglink' href='#frag'>fragment link</a>";
std::string document_write_script = JsReplace(
"var iframe = document.getElementById('frame');"
"iframe.contentWindow.document.write($1);"
"iframe.contentWindow.document.close();",
html);
EXPECT_TRUE(ExecJs(root, document_write_script));
EXPECT_EQ(opaque_origin, root->current_origin());
EXPECT_EQ(opaque_origin, frame->current_origin());
GURL frame_url_2("data:text/html,Top level page#frag");
std::string link_script = "document.getElementById('fraglink').click()";
EXPECT_TRUE(ExecJs(frame, link_script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(opaque_origin, root->current_origin());
EXPECT_EQ(opaque_origin, frame->current_origin());
EXPECT_EQ(ListValueOf("Top level page", "fragment link"),
EvalJs(frame,
"[window.parent.document.body.textContent,"
" document.body.textContent]"))
<< "Frames should be same-origin and able to script each other.";
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(2, EvalJs(root, "history.length"));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(frame_url_2, frame->current_url());
{
TestNavigationObserver observer(shell()->web_contents(), 1);
controller.GoBack();
observer.Wait();
}
EXPECT_EQ("ping", EvalJs(root, "'ping'"));
EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
EXPECT_EQ(blank_url, frame->current_url());
EXPECT_EQ(opaque_origin, frame->current_origin());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
ForwardInSubframeWithPendingForward) {
DisableBackForwardCacheForTesting(shell()->web_contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
GURL url_a(embedded_test_server()->GetURL(
"/navigation_controller/page_with_data_iframe.html"));
GURL frame_url_a1("data:text/html,Subframe");
EXPECT_TRUE(NavigateToURL(shell(), url_a));
NavigationController& controller = shell()->web_contents()->GetController();
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(1U, root->child_count());
EXPECT_EQ(url_a, root->current_url());
FrameTreeNode* frame = root->child_at(0);
EXPECT_EQ(frame_url_a1, frame->current_url());
GURL frame_url_a2 = embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html");
EXPECT_TRUE(NavigateToURLFromRenderer(frame, frame_url_a2));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(url_a, root->current_url());
EXPECT_EQ(frame_url_a2, frame->current_url());
GURL url_b(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe.html"));
GURL frame_url_2(url::kAboutBlankURL);
EXPECT_TRUE(NavigateToURL(shell(), url_b));
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(url_b, root->current_url());
EXPECT_EQ(frame_url_2, root->child_at(0)->current_url());
ASSERT_TRUE(controller.CanGoToOffset(-2));
controller.GoToOffset(-2);
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(url_a, root->current_url());
EXPECT_EQ(frame_url_a1, root->child_at(0)->current_url());
FrameTestNavigationManager subframe_delayer(
root->child_at(0)->frame_tree_node_id(), shell()->web_contents(),
frame_url_a2);
TestNavigationManager mainframe_delayer(shell()->web_contents(), url_b);
controller.GoForward();
EXPECT_TRUE(subframe_delayer.WaitForRequestStart());
controller.GoForward();
EXPECT_TRUE(mainframe_delayer.WaitForRequestStart());
EXPECT_EQ(2, controller.GetPendingEntryIndex());
ASSERT_TRUE(subframe_delayer.WaitForNavigationFinished());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(url_a, root->current_url());
EXPECT_EQ(frame_url_a2, root->child_at(0)->current_url());
ASSERT_TRUE(mainframe_delayer.WaitForNavigationFinished());
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(url_b, root->current_url());
EXPECT_EQ(frame_url_2, root->child_at(0)->current_url());
NavigationEntry* entry = controller.GetEntryAtIndex(1);
EXPECT_EQ(url_a, entry->GetURL());
blink::ExplodedPageState exploded_state;
EXPECT_TRUE(blink::DecodePageState(entry->GetPageState().ToEncodedData(),
&exploded_state));
EXPECT_EQ(url_a,
GURL(exploded_state.top.url_string.value_or(std::u16string())));
EXPECT_EQ(frame_url_a2,
GURL(exploded_state.top.children.at(0).url_string.value_or(
std::u16string())));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
AbortProvisionalLoadRetainsNavigationParams) {
EXPECT_TRUE(
NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
EXPECT_TRUE(
NavigateToURL(shell(), embedded_test_server()->GetURL("/title2.html")));
TestNavigationManager delayer(shell()->web_contents(),
embedded_test_server()->GetURL("/title3.html"));
shell()->LoadURL(embedded_test_server()->GetURL("/title3.html"));
EXPECT_TRUE(delayer.WaitForRequestStart());
NavigationController& controller = shell()->web_contents()->GetController();
controller.GoBack();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_TRUE(controller.CanGoForward());
EXPECT_EQ(0, controller.GetCurrentEntryIndex());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, NavigateTo304) {
GURL initial_url = embedded_test_server()->GetURL("/set-header");
GURL not_modified_url = embedded_test_server()->GetURL("/echo?status=304");
EXPECT_TRUE(NavigateToURL(shell(), initial_url));
EXPECT_EQ(initial_url, shell()->web_contents()->GetVisibleURL());
EXPECT_FALSE(NavigateToURL(shell(), not_modified_url));
EXPECT_EQ(initial_url, shell()->web_contents()->GetVisibleURL());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
PageStateAfterForwardInCompetingFrames) {
if (ShouldCreateNewHostForSameSiteSubframe())
return;
GURL url_a(embedded_test_server()->GetURL(
"/navigation_controller/page_with_data_iframe.html"));
GURL frame_url_a1("data:text/html,Subframe");
EXPECT_TRUE(NavigateToURL(shell(), url_a));
NavigationController& controller = shell()->web_contents()->GetController();
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(url_a, root->current_url());
EXPECT_EQ(frame_url_a1, root->child_at(0)->current_url());
GURL frame_url_a2 = embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html");
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url_a2));
GURL blank_url(url::kAboutBlankURL);
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), blank_url));
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(url_a, root->current_url());
EXPECT_EQ(blank_url, root->child_at(0)->current_url());
controller.GoBack();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
GURL url_b(embedded_test_server()->GetURL(
"b.com", "/navigation_controller/simple_page_2.html"));
std::string replace_script = "location.replace('" + url_b.spec() + "')";
TestNavigationObserver replace_observer(shell()->web_contents());
EXPECT_TRUE(ExecJs(shell()->web_contents(), replace_script));
replace_observer.Wait();
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(url_b, root->current_url());
controller.GoBack();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_TRUE(
ExecJs(shell()->web_contents(), "history.forward(); history.forward();"));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(url_b, root->current_url());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(url_b, entry->GetURL());
blink::ExplodedPageState exploded_state;
EXPECT_TRUE(blink::DecodePageState(entry->GetPageState().ToEncodedData(),
&exploded_state));
EXPECT_EQ(url_b,
GURL(exploded_state.top.url_string.value_or(std::u16string())));
EXPECT_EQ(0U, exploded_state.top.children.size());
controller.GoBack();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
controller.GoForward();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
ASSERT_TRUE(root->current_frame_host()->IsRenderFrameLive());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(url_b, shell()->web_contents()->GetVisibleURL());
EXPECT_EQ(url_b, root->current_url());
EXPECT_EQ(0U, root->child_count());
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
DISABLED_PageStateWithIframeAfterForwardInCompetingFrames) {
GURL url_a(embedded_test_server()->GetURL(
"/navigation_controller/page_with_data_iframe.html"));
GURL data_url("data:text/html,Subframe");
EXPECT_TRUE(NavigateToURL(shell(), url_a));
NavigationController& controller = shell()->web_contents()->GetController();
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(url_a, root->current_url());
EXPECT_EQ(data_url, root->child_at(0)->current_url());
GURL frame_url_a1 = embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html");
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url_a1));
GURL frame_url_a2 = embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html");
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url_a2));
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(url_a, root->current_url());
EXPECT_EQ(frame_url_a2, root->child_at(0)->current_url());
controller.GoBack();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
GURL url_b(embedded_test_server()->GetURL(
"b.com", "/navigation_controller/page_with_data_iframe.html"));
std::string replace_script = "location.replace('" + url_b.spec() + "')";
TestNavigationObserver replace_observer(shell()->web_contents());
EXPECT_TRUE(ExecJs(shell()->web_contents(), replace_script));
replace_observer.Wait();
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(url_b, root->current_url());
EXPECT_EQ(data_url, root->child_at(0)->current_url());
controller.GoBack();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_TRUE(
ExecJs(shell()->web_contents(), "history.forward(); history.forward();"));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
EXPECT_EQ(url_b, root->current_url());
EXPECT_EQ(data_url, root->child_at(0)->current_url());
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(url_b, entry->GetURL());
blink::ExplodedPageState exploded_state;
EXPECT_TRUE(blink::DecodePageState(entry->GetPageState().ToEncodedData(),
&exploded_state));
EXPECT_EQ(url_b,
GURL(exploded_state.top.url_string.value_or(std::u16string())));
controller.GoBack();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
controller.GoForward();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
ASSERT_TRUE(root->current_frame_host()->IsRenderFrameLive());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(url_b, shell()->web_contents()->GetVisibleURL());
EXPECT_EQ(url_b, root->current_url());
EXPECT_EQ(data_url, root->child_at(0)->current_url());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
ForwardRedirectWithNoCommittedEntry) {
NavigationController& controller = shell()->web_contents()->GetController();
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL url_1(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_1));
GURL url_2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_2));
EXPECT_EQ(url_2, root->current_url());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
GURL url_3(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/page_with_links.html"));
{
TestNavigationObserver observer(shell()->web_contents());
std::string script =
"history.replaceState({}, '', '/server-redirect?" + url_3.spec() + "')";
EXPECT_TRUE(ExecJs(root, script));
observer.Wait();
}
controller.GoBack();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(url_1, root->current_url());
std::unique_ptr<WebContents> new_tab = shell()->web_contents()->Clone();
WebContentsImpl* new_tab_impl = static_cast<WebContentsImpl*>(new_tab.get());
NavigationController& new_controller = new_tab_impl->GetController();
FrameTreeNode* new_root = new_tab_impl->GetPrimaryFrameTree().root();
EXPECT_TRUE(new_controller.IsInitialNavigation());
EXPECT_TRUE(new_controller.NeedsReload());
{
TestNavigationObserver observer(new_tab.get());
new_controller.GoForward();
observer.Wait();
}
EXPECT_TRUE(new_root->current_frame_host()->IsRenderFrameLive());
EXPECT_EQ(url_3, new_root->current_url());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
SubframeForwardRedirect) {
NavigationController& controller = shell()->web_contents()->GetController();
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL url_1(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/page_with_data_iframe.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_1));
GURL frame_url(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url));
EXPECT_EQ(url_1, root->current_url());
EXPECT_EQ(frame_url, root->child_at(0)->current_url());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
GURL frame_url2(embedded_test_server()->GetURL(
"bar.com", "/navigation_controller/simple_page_2.html"));
{
TestNavigationObserver observer(shell()->web_contents());
std::string script = "history.replaceState({}, '', '/server-redirect?" +
frame_url2.spec() + "')";
EXPECT_TRUE(ExecJs(root->child_at(0), script));
observer.Wait();
}
{
TestNavigationObserver observer(shell()->web_contents());
controller.GoBack();
observer.Wait();
}
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(url_1, root->current_url());
{
TestNavigationObserver observer(shell()->web_contents());
controller.GoForward();
observer.Wait();
}
EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
EXPECT_EQ(url_1, root->current_url());
EXPECT_EQ(frame_url2, root->child_at(0)->current_url());
if (AreAllSitesIsolatedForTesting()) {
EXPECT_EQ(GURL("http://bar.com"), root->child_at(0)
->current_frame_host()
->GetSiteInstance()
->GetSiteURL());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, PostInSubframe) {
GURL page_with_form_url = embedded_test_server()->GetURL(
"/navigation_controller/subframe_form.html");
EXPECT_TRUE(NavigateToURL(shell(), page_with_form_url));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
FrameTreeNode* frame = root->child_at(0);
EXPECT_EQ(1, controller.GetEntryCount());
{
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
scoped_refptr<FrameNavigationEntry> root_entry = entry->GetFrameEntry(root);
scoped_refptr<FrameNavigationEntry> frame_entry =
entry->GetFrameEntry(frame);
EXPECT_NE(nullptr, root_entry);
EXPECT_NE(nullptr, frame_entry);
EXPECT_EQ("GET", root_entry->method());
EXPECT_EQ(-1, root_entry->post_id());
EXPECT_EQ("GET", frame_entry->method());
EXPECT_EQ(-1, frame_entry->post_id());
EXPECT_FALSE(entry->GetHasPostData());
EXPECT_EQ(-1, entry->GetPostID());
}
TestNavigationObserver observer(shell()->web_contents(), 1);
ExecuteScriptAsync(shell(), "submitForm('isubmit')");
observer.Wait();
EXPECT_EQ(2, controller.GetEntryCount());
{
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
scoped_refptr<FrameNavigationEntry> root_entry = entry->GetFrameEntry(root);
scoped_refptr<FrameNavigationEntry> frame_entry =
entry->GetFrameEntry(frame);
EXPECT_NE(nullptr, root_entry);
EXPECT_NE(nullptr, frame_entry);
EXPECT_EQ("GET", root_entry->method());
EXPECT_EQ(-1, root_entry->post_id());
EXPECT_EQ("POST", frame_entry->method());
EXPECT_NE(-1, frame_entry->post_id());
EXPECT_FALSE(entry->GetHasPostData());
EXPECT_EQ(-1, entry->GetPostID());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, PostViaOpenUrlMsg) {
GURL main_url(
embedded_test_server()->GetURL("/form_that_posts_to_echoall.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
shell()
->web_contents()
->GetMutableRendererPrefs()
->browser_handles_all_top_level_requests = true;
shell()->web_contents()->SyncRendererPrefs();
TestNavigationObserver form_post_observer(shell()->web_contents(), 1);
EXPECT_TRUE(ExecJs(shell()->web_contents(),
"document.getElementById('form').submit();"));
form_post_observer.Wait();
GURL target_url(embedded_test_server()->GetURL("/echoall"));
EXPECT_EQ(target_url, shell()->web_contents()->GetLastCommittedURL());
EXPECT_EQ(
"text=value\n",
EvalJs(shell(), "document.getElementsByTagName('pre')[0].innerText"));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, UncacheablePost) {
GURL main_url(embedded_test_server()->GetURL(
"initial-page.example.com", "/form_that_posts_to_echoall_nocache.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
WebContents* web_contents = shell()->web_contents();
EXPECT_EQ(0, web_contents->GetController().GetLastCommittedEntryIndex());
GURL target_url(
embedded_test_server()->GetURL("another-site.com", "/echoall/nocache"));
ASSERT_TRUE(ExecJs(
web_contents,
JsReplace("document.getElementById('form').action = $1", target_url)));
TestNavigationObserver form_post_observer(web_contents, 1);
EXPECT_TRUE(
ExecJs(web_contents, "document.getElementById('form').submit();"));
form_post_observer.Wait();
EXPECT_EQ(target_url, web_contents->GetLastCommittedURL());
EXPECT_EQ(1, web_contents->GetController().GetLastCommittedEntryIndex());
std::string request_headers =
EvalJs(web_contents, "document.getElementsByTagName('pre')[1].innerText;")
.ExtractString();
EXPECT_THAT(request_headers, ::testing::HasSubstr("POST /echoall/nocache"));
EXPECT_EQ("text=value\n",
EvalJs(web_contents,
"document.getElementsByTagName('pre')[0].innerText;"));
std::string old_response_nonce =
EvalJs(web_contents,
"document.getElementById('response-nonce').innerText")
.ExtractString();
EXPECT_THAT(EvalJs(web_contents,
"document.getElementById('request-headers').innerText")
.ExtractString(),
::testing::HasSubstr("Origin: http://initial-page.example.com"));
{
TestNavigationObserver observer(web_contents);
web_contents->GetController().GoBack();
observer.Wait();
}
EXPECT_EQ(main_url, web_contents->GetLastCommittedURL());
EXPECT_EQ(0, web_contents->GetController().GetLastCommittedEntryIndex());
{
TestNavigationObserver navigation_observer(web_contents);
NavigationHandleObserver handle_observer(web_contents, target_url);
web_contents->GetController().GoForward();
navigation_observer.Wait();
EXPECT_TRUE(handle_observer.is_error());
EXPECT_EQ(net::ERR_CACHE_MISS, handle_observer.net_error_code());
}
EXPECT_EQ(target_url, web_contents->GetLastCommittedURL());
EXPECT_EQ(1, web_contents->GetController().GetLastCommittedEntryIndex());
{
TestNavigationObserver observer(web_contents);
web_contents->GetController().Reload(content::ReloadType::NORMAL,
false);
observer.Wait();
}
EXPECT_EQ(target_url, web_contents->GetLastCommittedURL());
EXPECT_EQ(1, web_contents->GetController().GetLastCommittedEntryIndex());
request_headers =
EvalJs(web_contents, "document.getElementsByTagName('pre')[1].innerText;")
.ExtractString();
EXPECT_THAT(request_headers, ::testing::HasSubstr("POST /echoall/nocache"));
EXPECT_EQ("text=value\n",
EvalJs(web_contents,
"document.getElementsByTagName('pre')[0].innerText;"));
EXPECT_NE(old_response_nonce,
EvalJs(web_contents,
"document.getElementById('response-nonce').innerText"));
EXPECT_THAT(EvalJs(web_contents,
"document.getElementById('request-headers').innerText")
.ExtractString(),
::testing::HasSubstr("Origin: http://initial-page.example.com"));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
ReloadOfInitiallyFailedPost) {
GURL main_url(embedded_test_server()->GetURL(
"/form_that_posts_to_echoall_nocache.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
WebContents* web_contents = shell()->web_contents();
EXPECT_EQ(0, web_contents->GetController().GetLastCommittedEntryIndex());
GURL target_url(embedded_test_server()->GetURL("/echoall/nocache"));
{
std::unique_ptr<URLLoaderInterceptor> interceptor =
URLLoaderInterceptor::SetupRequestFailForURL(
target_url, net::ERR_INTERNET_DISCONNECTED);
TestNavigationObserver form_post_observer(web_contents, 1);
EXPECT_TRUE(
ExecJs(web_contents, "document.getElementById('form').submit();"));
form_post_observer.Wait();
}
EXPECT_EQ(target_url, web_contents->GetLastCommittedURL());
EXPECT_EQ(1, web_contents->GetController().GetLastCommittedEntryIndex());
{
TestNavigationObserver observer(web_contents);
web_contents->GetController().Reload(content::ReloadType::NORMAL,
false);
observer.Wait();
}
EXPECT_EQ(target_url, web_contents->GetLastCommittedURL());
EXPECT_EQ(1, web_contents->GetController().GetLastCommittedEntryIndex());
std::string request_headers =
EvalJs(web_contents, "document.getElementsByTagName('pre')[1].innerText;")
.ExtractString();
EXPECT_THAT(request_headers, ::testing::HasSubstr("POST /echoall/nocache"));
EXPECT_EQ("text=value\n",
EvalJs(web_contents,
"document.getElementsByTagName('pre')[0].innerText;"));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
DISABLED_EnsureFrameNavigationEntriesClearedOnMismatch) {
WebContentsImpl* web_contents =
static_cast<WebContentsImpl*>(shell()->web_contents());
NavigationControllerImpl& controller = web_contents->GetController();
FrameTreeNode* root = web_contents->GetPrimaryFrameTree().root();
GURL start_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
EXPECT_EQ(3U, root->child_count());
EXPECT_EQ(2U, root->child_at(0)->child_count());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
{
scoped_refptr<FrameNavigationEntry> root_entry = entry->GetFrameEntry(root);
EXPECT_NE(nullptr, root_entry);
EXPECT_EQ("", root_entry->frame_unique_name());
EXPECT_EQ(3U, entry->root_node()->children.size());
EXPECT_EQ(2U, entry->root_node()->children[0]->children.size());
FrameTreeNode* frame = root->child_at(0)->child_at(0);
NavigationEntryImpl::TreeNode* tree_node = entry->GetTreeNode(frame);
scoped_refptr<FrameNavigationEntry> frame_entry =
entry->GetFrameEntry(frame);
EXPECT_NE(nullptr, tree_node);
EXPECT_NE(nullptr, frame_entry);
EXPECT_EQ("1-1: 2-1: name", frame_entry->frame_unique_name());
EXPECT_EQ(frame_entry, tree_node->frame_entry);
EXPECT_EQ(0U, tree_node->children.size());
}
EXPECT_TRUE(ExecJs(root, kRemoveFrameScript));
EXPECT_EQ(2U, root->child_count());
{
scoped_refptr<FrameNavigationEntry> root_entry = entry->GetFrameEntry(root);
EXPECT_NE(nullptr, root_entry);
EXPECT_EQ(3U, entry->root_node()->children.size());
EXPECT_EQ(2U, entry->root_node()->children[0]->children.size());
NavigationEntryImpl::TreeNode* tree_node = nullptr;
for (auto& node : entry->root_node()->children[0]->children) {
if (node->frame_entry->frame_unique_name() == "1-1: 2-1: name") {
tree_node = node.get();
break;
}
}
EXPECT_TRUE(tree_node);
EXPECT_EQ(0U, tree_node->children.size());
}
FrameTreeNode* subframe = root->child_at(1)->child_at(1)->child_at(0);
EXPECT_EQ(2U, root->child_at(1)->child_count());
EXPECT_EQ(0U, subframe->child_count());
std::string add_matching_name_frame_script =
"var f = document.createElement('iframe');"
"f.name = '1-1-name';"
"f.src = '1-1.html';"
"document.body.appendChild(f);";
TestNavigationObserver observer(web_contents, 1);
EXPECT_TRUE(ExecJs(subframe, add_matching_name_frame_script));
EXPECT_EQ(1U, subframe->child_count());
observer.Wait();
{
scoped_refptr<FrameNavigationEntry> root_entry = entry->GetFrameEntry(root);
EXPECT_NE(nullptr, root_entry);
EXPECT_EQ(3U, entry->root_node()->children.size());
EXPECT_EQ(0U, entry->root_node()->children[0]->children.size());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
EnsureFirstLevelFrameNavigationEntriesMatch) {
WebContentsImpl* web_contents =
static_cast<WebContentsImpl*>(shell()->web_contents());
FrameTreeNode* root = web_contents->GetPrimaryFrameTree().root();
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
NavigationEntryImpl* nav_entry =
web_contents->GetController().GetLastCommittedEntry();
EXPECT_TRUE(ExecJs(root, kAddNamedFrameScript));
EXPECT_EQ(1U, root->child_count());
EXPECT_EQ(1U, nav_entry->root_node()->children.size());
scoped_refptr<FrameNavigationEntry> old_fne =
nav_entry->root_node()->children[0]->frame_entry;
EXPECT_TRUE(ExecJs(root, kRemoveFrameScript));
EXPECT_EQ(0U, root->child_count());
EXPECT_EQ(0U, nav_entry->root_node()->children.size());
EXPECT_TRUE(ExecJs(root, kAddNamedFrameScript));
EXPECT_EQ(1U, root->child_count());
EXPECT_EQ(1U, nav_entry->root_node()->children.size());
scoped_refptr<FrameNavigationEntry> new_fne =
nav_entry->root_node()->children[0]->frame_entry;
EXPECT_TRUE(old_fne->HasOneRef());
EXPECT_NE(old_fne.get(), new_fne.get());
EXPECT_TRUE(ExecJs(root, kRemoveFrameScript));
EXPECT_EQ(0U, root->child_count());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
EnsureSameURLNavigationUpdatesFrameNavigationEntry) {
WebContentsImpl* web_contents =
static_cast<WebContentsImpl*>(shell()->web_contents());
FrameTreeNode* root = web_contents->GetPrimaryFrameTree().root();
GURL start_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
GURL fragment_change_url(
embedded_test_server()->GetURL("a.com", "/title1.html#foo"));
EXPECT_TRUE(NavigateToURL(shell(), fragment_change_url));
EXPECT_EQ(2, web_contents->GetController().GetEntryCount());
{
GURL redirect_dest_url(
embedded_test_server()->GetURL("sub.a.com", "/simple_page.html"));
TestNavigationObserver observer(web_contents);
std::string script = "history.replaceState({}, '', '/server-redirect?" +
redirect_dest_url.spec() + "')";
EXPECT_TRUE(ExecJs(root, script));
observer.Wait();
}
{
TestNavigationObserver observer(web_contents);
web_contents->GetController().LoadURL(web_contents->GetLastCommittedURL(),
Referrer(), ui::PAGE_TRANSITION_LINK,
std::string());
observer.Wait();
}
{
TestNavigationObserver observer(web_contents);
web_contents->GetController().GoBack();
observer.Wait();
}
EXPECT_EQ(url::Origin::Create(start_url).Serialize(),
EvalJs(web_contents, "self.origin"));
}
class HistoryNavigationBeforeCommitInjector
: public DidCommitNavigationInterceptor {
public:
HistoryNavigationBeforeCommitInjector(WebContentsImpl* web_contents,
const GURL& url)
: DidCommitNavigationInterceptor(web_contents),
did_trigger_history_navigation_(false),
url_(url) {}
HistoryNavigationBeforeCommitInjector(
const HistoryNavigationBeforeCommitInjector&) = delete;
HistoryNavigationBeforeCommitInjector& operator=(
const HistoryNavigationBeforeCommitInjector&) = delete;
~HistoryNavigationBeforeCommitInjector() override {}
bool did_trigger_history_navigation() const {
return did_trigger_history_navigation_;
}
private:
bool WillProcessDidCommitNavigation(
RenderFrameHost* render_frame_host,
NavigationRequest* navigation_request,
mojom::DidCommitProvisionalLoadParamsPtr* params,
mojom::DidCommitProvisionalLoadInterfaceParamsPtr* interface_params)
override {
if (!render_frame_host->GetParent() && (**params).url == url_) {
did_trigger_history_navigation_ = true;
web_contents()->GetController().GoBack();
}
return true;
}
bool did_trigger_history_navigation_;
GURL url_;
};
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
RaceCrossOriginNavigationAndSameDocumentHistoryNavigation) {
if (CanSameSiteMainFrameNavigationsChangeRenderFrameHosts()) {
return;
}
WebContentsImpl* web_contents =
static_cast<WebContentsImpl*>(shell()->web_contents());
FrameTreeNode* root = web_contents->GetPrimaryFrameTree().root();
GURL start_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
GURL same_document_url(
embedded_test_server()->GetURL("a.com", "/title1.html#foo"));
EXPECT_TRUE(NavigateToURL(shell(), same_document_url));
EXPECT_EQ(2, web_contents->GetController().GetEntryCount());
GURL cross_origin_url(
embedded_test_server()->GetURL("suborigin.a.com", "/title2.html"));
HistoryNavigationBeforeCommitInjector trigger(web_contents, cross_origin_url);
UrlCommitObserver cross_origin_commit_observer(root, cross_origin_url);
UrlCommitObserver history_commit_observer(root, start_url);
shell()->LoadURL(cross_origin_url);
cross_origin_commit_observer.Wait();
EXPECT_EQ(cross_origin_url, web_contents->GetLastCommittedURL());
EXPECT_EQ(2, web_contents->GetController().GetLastCommittedEntryIndex());
EXPECT_TRUE(trigger.did_trigger_history_navigation());
history_commit_observer.Wait();
EXPECT_EQ(start_url, web_contents->GetLastCommittedURL());
EXPECT_EQ(0, web_contents->GetController().GetLastCommittedEntryIndex());
EXPECT_EQ(3, web_contents->GetController().GetEntryCount());
EXPECT_EQ(url::Origin::Create(start_url).Serialize(),
EvalJs(web_contents, "self.origin"));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
OnCommitTimeoutAfterResetForCrossDocumentRestart) {
if (CanSameSiteMainFrameNavigationsChangeRenderFrameHosts()) {
return;
}
WebContentsImpl* web_contents =
static_cast<WebContentsImpl*>(shell()->web_contents());
FrameTreeNode* root = web_contents->GetPrimaryFrameTree().root();
GURL start_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
GURL same_document_url(
embedded_test_server()->GetURL("a.com", "/title1.html#foo"));
EXPECT_TRUE(NavigateToURL(shell(), same_document_url));
EXPECT_EQ(2, web_contents->GetController().GetEntryCount());
GURL cross_origin_url(
embedded_test_server()->GetURL("suborigin.a.com", "/title2.html"));
HistoryNavigationBeforeCommitInjector trigger(web_contents, cross_origin_url);
NavigationRequest::SetCommitTimeoutForTesting(base::Microseconds(1));
UrlCommitObserver cross_origin_commit_observer(root, cross_origin_url);
UrlCommitObserver history_commit_observer(root, start_url);
shell()->LoadURL(cross_origin_url);
cross_origin_commit_observer.Wait();
EXPECT_EQ(cross_origin_url, web_contents->GetLastCommittedURL());
EXPECT_EQ(2, web_contents->GetController().GetLastCommittedEntryIndex());
history_commit_observer.Wait();
EXPECT_EQ(start_url, web_contents->GetLastCommittedURL());
EXPECT_EQ(0, web_contents->GetController().GetLastCommittedEntryIndex());
NavigationRequest::SetCommitTimeoutForTesting(base::TimeDelta());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTestNoServer,
SameDocumentNavigationRaceWithCrossDocumentNavigation) {
net::test_server::ControllableHttpResponse response_success(
embedded_test_server(), "/title1.html");
ASSERT_TRUE(embedded_test_server()->Start());
WebContentsImpl* web_contents =
static_cast<WebContentsImpl*>(shell()->web_contents());
FrameTreeNode* root = web_contents->GetPrimaryFrameTree().root();
GURL start_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
{
UrlCommitObserver history_commit_observer(root, start_url);
shell()->LoadURL(start_url);
response_success.WaitForRequest();
response_success.Send(
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"Cache-Control: no-cache, no-store\r\n"
"\r\n"
"The server speaks HTTP!");
response_success.Done();
history_commit_observer.Wait();
EXPECT_EQ(0, web_contents->GetController().GetLastCommittedEntryIndex());
}
{
GURL same_document_url(
embedded_test_server()->GetURL("a.com", "/title1.html#foo"));
EXPECT_TRUE(NavigateToURL(shell(), same_document_url));
EXPECT_EQ(1, web_contents->GetController().GetLastCommittedEntryIndex());
}
{
NavigationHandleCommitObserver back_navigation(web_contents, start_url);
GURL cross_document_url(
embedded_test_server()->GetURL("a.com", "/title2.html"));
HistoryNavigationBeforeCommitInjector trigger(web_contents,
cross_document_url);
UrlCommitObserver cross_doc_commit_observer(root, cross_document_url);
shell()->LoadURL(cross_document_url);
EXPECT_TRUE(web_contents->GetController().GetPendingEntry());
cross_doc_commit_observer.Wait();
EXPECT_EQ(cross_document_url, web_contents->GetLastCommittedURL());
EXPECT_EQ(2, web_contents->GetController().GetLastCommittedEntryIndex());
EXPECT_TRUE(trigger.did_trigger_history_navigation());
if (ShouldCreateNewHostForAllFrames()) {
EXPECT_EQ(ShouldAvoidRedundantNavigationCancellations(),
!!root->navigation_request());
return;
}
EXPECT_TRUE(root->navigation_request());
EXPECT_EQ(root->navigation_request()->common_params().url.spec(),
start_url.spec());
EXPECT_FALSE(root->navigation_request()->IsSameDocument());
UrlCommitObserver back_history_commit_observer(root, start_url);
back_history_commit_observer.Wait();
EXPECT_FALSE(root->navigation_request());
EXPECT_FALSE(root->current_frame_host()->HasPendingCommitNavigation());
EXPECT_TRUE(back_navigation.has_committed());
EXPECT_FALSE(back_navigation.was_same_document());
EXPECT_EQ(0, web_contents->GetController().GetLastCommittedEntryIndex());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
RefererAndOriginHeadersAfterRedirects) {
GURL form_url(embedded_test_server()->GetURL(
"a.com", "/form_that_posts_cross_site.html"));
GURL redirect_target_url(embedded_test_server()->GetURL("x.com", "/echoall"));
EXPECT_TRUE(NavigateToURL(shell(), form_url));
TestNavigationObserver form_post_observer(shell()->web_contents(), 1);
EXPECT_TRUE(
ExecJs(shell(), "document.getElementById('text-form').submit();"));
form_post_observer.Wait();
EXPECT_EQ(redirect_target_url,
shell()->web_contents()->GetLastCommittedURL());
std::string headers =
EvalJs(shell(), "document.getElementsByTagName('pre')[1].innerText")
.ExtractString();
EXPECT_THAT(headers, ::testing::HasSubstr("Origin: null"));
EXPECT_THAT(headers, ::testing::ContainsRegex("Referer: http://a.com:.*/"));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
ContentTypeHeaderAfterRedirectAndRefresh) {
GURL form_url(embedded_test_server()->GetURL(
"a.com", "/form_that_posts_cross_site.html"));
GURL redirect_target_url(embedded_test_server()->GetURL("x.com", "/echoall"));
EXPECT_TRUE(NavigateToURL(shell(), form_url));
TestNavigationObserver form_post_observer(shell()->web_contents(), 1);
EXPECT_TRUE(
ExecJs(shell(), "document.getElementById('text-form').submit();"));
form_post_observer.Wait();
EXPECT_EQ(redirect_target_url,
shell()->web_contents()->GetLastCommittedURL());
std::string headers =
EvalJs(shell(), "document.getElementsByTagName('pre')[1].innerText")
.ExtractString();
EXPECT_THAT(headers, ::testing::HasSubstr(
"Content-Type: application/x-www-form-urlencoded"));
TestNavigationObserver reload_observer(shell()->web_contents(), 1);
ASSERT_TRUE(ExecJs(shell(), "location.reload()"));
reload_observer.Wait();
headers = EvalJs(shell(), "document.getElementsByTagName('pre')[1].innerText")
.ExtractString();
EXPECT_THAT(headers, ::testing::HasSubstr(
"Content-Type: application/x-www-form-urlencoded"));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
SameDocumentNavigationDoesNotClearFavicon) {
NavigationController& controller = shell()->web_contents()->GetController();
ASSERT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL("/simple_page.html")));
NavigationEntry* entry = controller.GetLastCommittedEntry();
ASSERT_TRUE(entry);
content::FaviconStatus& favicon_status = entry->GetFavicon();
favicon_status.valid = true;
ASSERT_TRUE(RendererLocationReplace(
shell(), embedded_test_server()->GetURL(
"/simple_page.html#same-document-navigation")));
entry = controller.GetLastCommittedEntry();
content::FaviconStatus& favicon_status2 = entry->GetFavicon();
EXPECT_TRUE(favicon_status2.valid);
ASSERT_TRUE(RendererLocationReplace(
shell(),
embedded_test_server()->GetURL("/simple_page.html?new-navigation")));
entry = controller.GetLastCommittedEntry();
content::FaviconStatus& favicon_status3 = entry->GetFavicon();
EXPECT_FALSE(favicon_status3.valid);
}
namespace {
class AllowDialogInterceptor
: public blink::mojom::LocalFrameHostInterceptorForTesting {
public:
AllowDialogInterceptor() = default;
~AllowDialogInterceptor() override = default;
void Init(RenderFrameHostImpl* render_frame_host) {
render_frame_host_ = render_frame_host;
std::ignore = render_frame_host_->local_frame_host_receiver_for_testing()
.SwapImplForTesting(this);
}
blink::mojom::LocalFrameHost* GetForwardingInterface() override {
return render_frame_host_;
}
void RunModalAlertDialog(const std::u16string& alert_message,
bool disable_third_party_subframe_suppresion,
RunModalAlertDialogCallback callback) override {
alert_callback_ = std::move(callback);
alert_message_ = alert_message;
}
void ResumeProcessingModalAlertDialogHandling() {
has_called_callback_ = true;
render_frame_host_->RunModalAlertDialog(alert_message_, false,
std::move(alert_callback_));
}
bool HasCalledAlertCallback() const { return has_called_callback_; }
private:
raw_ptr<RenderFrameHostImpl> render_frame_host_;
std::u16string alert_message_;
RunModalAlertDialogCallback alert_callback_;
bool has_called_callback_ = false;
};
class NavigationControllerAlertDialogBrowserTest
: public NavigationControllerBrowserTest,
public WebContentsObserver,
public WebContentsDelegate {
public:
void BindWebContents(WebContents* web_contents) {
alert_interceptor_.Init(
static_cast<RenderFrameHostImpl*>(web_contents->GetPrimaryMainFrame()));
Observe(web_contents);
web_contents->SetDelegate(this);
}
void DidFinishNavigation(NavigationHandle* navigation_handle) override {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!navigation_handle->HasCommitted())
return;
alert_interceptor_.ResumeProcessingModalAlertDialogHandling();
}
JavaScriptDialogManager* GetJavaScriptDialogManager(
WebContents* source) override {
CHECK(false);
return nullptr;
}
bool HasCalledAlertCallback() const {
return alert_interceptor_.HasCalledAlertCallback();
}
private:
AllowDialogInterceptor alert_interceptor_;
};
}
IN_PROC_BROWSER_TEST_P(NavigationControllerAlertDialogBrowserTest,
DISABLED_NoDialogsFromSwappedOutFrames) {
GURL url1 = embedded_test_server()->GetURL(
"/navigation_controller/beforeunload_dialog.html");
EXPECT_TRUE(NavigateToURL(shell(), url1));
WebContents* web_contents = shell()->web_contents();
BindWebContents(web_contents);
GURL url2(std::string(kChromeUIScheme) + url::kStandardSchemeSeparator +
kChromeUIGpuHost);
EXPECT_TRUE(NavigateToURL(shell(), url2));
EXPECT_TRUE(HasCalledAlertCallback());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
RefererStoredForSubFrame) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url_simple(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe_simple.html"));
GURL url_redirect(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe_redirect.html"));
for (const GURL& url : {url_simple, url_redirect}) {
EXPECT_TRUE(NavigateToURL(shell(), url));
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
ASSERT_EQ(1U, entry->root_node()->children.size());
scoped_refptr<FrameNavigationEntry> frame_entry =
entry->root_node()->children[0]->frame_entry.get();
EXPECT_EQ(frame_entry->referrer().url, url);
}
}
namespace {
class RequestMonitoringNavigationBrowserTest
: public NavigationControllerBrowserTest {
public:
RequestMonitoringNavigationBrowserTest() = default;
const net::test_server::HttpRequest* FindAccumulatedRequest(
const GURL& url_to_find) {
DCHECK(url_to_find.SchemeIsHTTPOrHTTPS());
auto it = base::ranges::find(accumulated_requests_, url_to_find,
&net::test_server::HttpRequest::GetURL);
if (it == accumulated_requests_.end())
return nullptr;
return &*it;
}
protected:
void SetUpOnMainThread() override {
embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
&RequestMonitoringNavigationBrowserTest::MonitorRequestOnIoThread,
weak_factory_.GetWeakPtr(),
base::SequencedTaskRunner::GetCurrentDefault()));
ASSERT_TRUE(embedded_test_server()->Start());
}
void TearDown() override {
EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
}
private:
static void MonitorRequestOnIoThread(
const base::WeakPtr<RequestMonitoringNavigationBrowserTest>& weak_this,
const scoped_refptr<base::SequencedTaskRunner>& postback_task_runner,
const net::test_server::HttpRequest& request) {
postback_task_runner->PostTask(
FROM_HERE,
base::BindOnce(
&RequestMonitoringNavigationBrowserTest::MonitorRequestOnMainThread,
weak_this, request));
}
void MonitorRequestOnMainThread(
const net::test_server::HttpRequest& request) {
accumulated_requests_.push_back(request);
}
std::vector<net::test_server::HttpRequest> accumulated_requests_;
base::WeakPtrFactory<RequestMonitoringNavigationBrowserTest> weak_factory_{
this};
};
class WebContentsLoadFinishedWaiter : public WebContentsObserver {
public:
WebContentsLoadFinishedWaiter(WebContents* web_contents,
const GURL& expected_url)
: WebContentsObserver(web_contents),
expected_url_(expected_url),
message_loop_runner_(new MessageLoopRunner) {
EXPECT_TRUE(web_contents != nullptr);
}
void Wait() { message_loop_runner_->Run(); }
private:
void DidFinishLoad(RenderFrameHost* render_frame_host,
const GURL& url) override {
bool is_main_frame = !render_frame_host->GetParent();
if (url == expected_url_ && is_main_frame)
message_loop_runner_->Quit();
}
GURL expected_url_;
scoped_refptr<MessageLoopRunner> message_loop_runner_;
};
}
IN_PROC_BROWSER_TEST_P(RequestMonitoringNavigationBrowserTest,
ExtraHeadersVsSubresources) {
GURL page_url = embedded_test_server()->GetURL("/page_with_image.html");
GURL image_url = embedded_test_server()->GetURL("/blank.jpg");
WebContentsLoadFinishedWaiter waiter(shell()->web_contents(), page_url);
NavigationController::LoadURLParams load_url_params(page_url);
load_url_params.extra_headers =
"X-ExtraHeadersVsSubresources: 1\n"
"X-2ExtraHeadersVsSubresources: 2";
shell()->web_contents()->GetController().LoadURLWithParams(load_url_params);
waiter.Wait();
EXPECT_EQ(page_url, shell()->web_contents()->GetLastCommittedURL());
const net::test_server::HttpRequest* page_request =
FindAccumulatedRequest(page_url);
ASSERT_TRUE(page_request);
EXPECT_THAT(page_request->headers,
testing::Contains(testing::Key("X-ExtraHeadersVsSubresources")));
EXPECT_THAT(page_request->headers,
testing::Contains(testing::Key("X-2ExtraHeadersVsSubresources")));
const net::test_server::HttpRequest* image_request =
FindAccumulatedRequest(image_url);
ASSERT_TRUE(image_request);
EXPECT_THAT(image_request->headers,
testing::Not(testing::Contains(
testing::Key("X-ExtraHeadersVsSubresources"))));
EXPECT_THAT(image_request->headers,
testing::Not(testing::Contains(
testing::Key("X-2ExtraHeadersVsSubresources"))));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
SameDocumentNavigationDoesntDeleteNavigationHandle) {
const GURL kURL1 = embedded_test_server()->GetURL("/title1.html");
const GURL kPushStateURL =
embedded_test_server()->GetURL("/title1.html#fragment");
const GURL kURL2 = embedded_test_server()->GetURL("/title2.html");
EXPECT_TRUE(NavigateToURL(shell(), kURL1));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_FALSE(root->navigation_request());
TestNavigationManager manager(shell()->web_contents(), kURL2);
NavigationHandleCommitObserver navigation_observer(shell()->web_contents(),
kURL2);
shell()->web_contents()->GetController().LoadURL(
kURL2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
EXPECT_TRUE(manager.WaitForRequestStart());
NavigationRequest* request = root->navigation_request();
EXPECT_TRUE(request);
NavigationHandleCommitObserver push_state_observer(shell()->web_contents(),
kPushStateURL);
std::string push_state =
JsReplace("history.pushState({}, 'title 1', $1);", kPushStateURL);
EXPECT_TRUE(ExecJs(shell()->web_contents(), push_state));
NavigationEntry* last_committed =
shell()->web_contents()->GetController().GetLastCommittedEntry();
ASSERT_TRUE(last_committed);
EXPECT_EQ(kPushStateURL, last_committed->GetURL());
EXPECT_TRUE(push_state_observer.has_committed());
EXPECT_TRUE(push_state_observer.was_same_document());
EXPECT_TRUE(push_state_observer.was_renderer_initiated());
EXPECT_TRUE(root->navigation_request());
EXPECT_EQ(request, root->navigation_request());
ASSERT_TRUE(manager.WaitForNavigationFinished());
last_committed =
shell()->web_contents()->GetController().GetLastCommittedEntry();
ASSERT_TRUE(last_committed);
EXPECT_EQ(kURL2, last_committed->GetURL());
EXPECT_TRUE(navigation_observer.has_committed());
EXPECT_FALSE(navigation_observer.was_same_document());
EXPECT_FALSE(navigation_observer.was_renderer_initiated());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
SameDocumentBrowserInitiated) {
const GURL kURL = embedded_test_server()->GetURL("/title1.html");
const GURL kFragmentURL =
embedded_test_server()->GetURL("/title1.html#fragment");
EXPECT_TRUE(NavigateToURL(shell(), kURL));
NavigationHandleCommitObserver handle_observer(shell()->web_contents(),
kFragmentURL);
EXPECT_TRUE(NavigateToURL(shell(), kFragmentURL));
EXPECT_TRUE(handle_observer.has_committed());
EXPECT_TRUE(handle_observer.was_same_document());
EXPECT_FALSE(handle_observer.was_renderer_initiated());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, 204Navigation) {
const GURL kURL = embedded_test_server()->GetURL("/title1.html");
const GURL kURL204 = embedded_test_server()->GetURL("/page204.html");
EXPECT_TRUE(NavigateToURL(shell(), kURL));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(kURL, entry->GetURL());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_FALSE(NavigateToURL(shell(), kURL204));
entry = controller.GetLastCommittedEntry();
EXPECT_EQ(kURL, entry->GetURL());
EXPECT_EQ(1, controller.GetEntryCount());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, NavigateToEmptyURL) {
GURL url_1 = embedded_test_server()->GetURL("/title1.html");
GURL url_2 = embedded_test_server()->GetURL("/title2.html");
GURL url_204 = embedded_test_server()->GetURL("/page204.html");
EXPECT_TRUE(NavigateToURL(shell(), url_1));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(url_1, entry->GetURL());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_TRUE(NavigateToURL(shell(), GURL(), GURL("about:blank")));
entry = controller.GetLastCommittedEntry();
EXPECT_EQ(GURL("about:blank"), entry->GetURL());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_TRUE(
contents()->GetPrimaryMainFrame()->GetLastCommittedOrigin().opaque());
EXPECT_FALSE(entry->root_node()->frame_entry->initiator_origin().has_value());
EXPECT_FALSE(NavigateToURLFromRenderer(shell(), GURL()));
EXPECT_EQ(entry, controller.GetLastCommittedEntry());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_TRUE(NavigateToURL(shell(), url_2));
const url::Origin& opener_origin =
contents()->GetPrimaryMainFrame()->GetLastCommittedOrigin();
{
Shell* new_shell = OpenWindow(contents(), url_204);
WebContentsImpl* new_contents =
static_cast<WebContentsImpl*>(new_shell->web_contents());
NavigationControllerImpl& new_controller = new_contents->GetController();
EXPECT_EQ(1, new_controller.GetEntryCount());
entry = new_controller.GetLastCommittedEntry();
EXPECT_TRUE(entry->IsInitialEntry());
EXPECT_EQ(GURL(), entry->GetURL());
scoped_refptr<FrameNavigationEntry> frame_entry =
entry->root_node()->frame_entry.get();
ASSERT_TRUE(frame_entry->initiator_origin().has_value());
EXPECT_EQ(opener_origin, frame_entry->initiator_origin().value());
EXPECT_EQ(opener_origin, new_shell->web_contents()
->GetPrimaryMainFrame()
->GetLastCommittedOrigin());
}
{
ShellAddedObserver new_shell_observer;
EXPECT_TRUE(
ExecJs(shell(), "window.open('/page204.html', '_blank', 'noopener');"));
Shell* new_shell = new_shell_observer.GetShell();
NavigationControllerImpl& new_controller =
static_cast<WebContentsImpl*>(new_shell->web_contents())
->GetController();
EXPECT_EQ(1, new_controller.GetEntryCount());
entry = new_controller.GetLastCommittedEntry();
EXPECT_TRUE(entry->IsInitialEntry());
EXPECT_EQ(GURL(), entry->GetURL());
scoped_refptr<FrameNavigationEntry> frame_entry =
entry->root_node()->frame_entry.get();
ASSERT_TRUE(frame_entry->initiator_origin().has_value());
EXPECT_NE(opener_origin, frame_entry->initiator_origin().value());
EXPECT_TRUE(frame_entry->initiator_origin()->opaque());
EXPECT_EQ(frame_entry->initiator_origin().value(),
new_shell->web_contents()
->GetPrimaryMainFrame()
->GetLastCommittedOrigin());
}
{
ShellAddedObserver new_shell_observer;
EXPECT_TRUE(ExecJs(shell(), "window.open('', '_blank', 'noopener');"));
Shell* new_shell = new_shell_observer.GetShell();
EXPECT_TRUE(WaitForLoadStop(new_shell->web_contents()));
NavigationControllerImpl& new_controller =
static_cast<WebContentsImpl*>(new_shell->web_contents())
->GetController();
EXPECT_EQ(1, new_controller.GetEntryCount());
entry = new_controller.GetLastCommittedEntry();
EXPECT_FALSE(entry->IsInitialEntry());
EXPECT_EQ(GURL("about:blank#blocked"), entry->GetURL());
scoped_refptr<FrameNavigationEntry> frame_entry =
entry->root_node()->frame_entry.get();
ASSERT_TRUE(frame_entry->initiator_origin().has_value());
EXPECT_EQ(opener_origin, frame_entry->initiator_origin().value());
EXPECT_EQ(opener_origin, new_shell->web_contents()
->GetPrimaryMainFrame()
->GetLastCommittedOrigin());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, StopDuringLoad) {
GURL start_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
GURL slow_url = embedded_test_server()->GetURL("/slow?60");
shell()->LoadURL(slow_url);
shell()->web_contents()->Stop();
NavigationController& controller = shell()->web_contents()->GetController();
ASSERT_EQ(controller.GetPendingEntry(), nullptr);
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, ReloadDoesntKeepTitle) {
NavigationController& controller = shell()->web_contents()->GetController();
GURL start_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
GURL intermediate_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
std::u16string title = u"title";
{
EXPECT_TRUE(NavigateToURL(shell(), start_url));
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_TRUE(entry->GetTitle().empty());
entry->SetTitle(title);
controller.Reload(ReloadType::NORMAL, false);
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_TRUE(entry->GetTitle().empty());
}
EXPECT_TRUE(NavigateToURL(shell(), intermediate_url));
{
EXPECT_TRUE(NavigateToURL(shell(), start_url));
NavigationEntry* entry = controller.GetLastCommittedEntry();
EXPECT_TRUE(entry->GetTitle().empty());
entry->SetTitle(title);
TestNavigationObserver reload_observer(shell()->web_contents());
EXPECT_TRUE(ExecJs(shell(), "location.reload()"));
reload_observer.Wait();
EXPECT_TRUE(entry->GetTitle().empty());
}
EXPECT_TRUE(NavigateToURL(shell(), intermediate_url));
{
EXPECT_TRUE(NavigateToURL(shell(), start_url));
NavigationEntry* entry1 = controller.GetLastCommittedEntry();
EXPECT_TRUE(entry1->GetTitle().empty());
entry1->SetTitle(title);
EXPECT_TRUE(NavigateToURL(shell(), start_url));
NavigationEntry* entry2 = controller.GetLastCommittedEntry();
EXPECT_EQ(entry1, entry2);
EXPECT_TRUE(entry1->GetTitle().empty());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
HistoryNavigationUsesCache) {
GURL no_cache_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_no_cache_header.html"));
GURL regular_url(embedded_test_server()->GetURL("/title2.html"));
NavigationController& controller = shell()->web_contents()->GetController();
EXPECT_TRUE(NavigateToURL(shell(), no_cache_url));
EXPECT_TRUE(NavigateToURL(shell(), regular_url));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
TestNavigationObserver back_observer(shell()->web_contents());
controller.GoBack();
back_observer.Wait();
EXPECT_TRUE(back_observer.last_navigation_succeeded());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
VerifyBlockedErrorPageURL_SessionHistory) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
GURL blocked_url(embedded_test_server()->GetURL("/blocked.html"));
std::unique_ptr<URLLoaderInterceptor> url_interceptor =
URLLoaderInterceptor::SetupRequestFailForURL(blocked_url,
net::ERR_BLOCKED_BY_CLIENT);
EXPECT_FALSE(NavigateToURL(shell(), blocked_url));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(PAGE_TYPE_ERROR, controller.GetLastCommittedEntry()->GetPageType());
EXPECT_TRUE(
NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
TestNavigationObserver back_load_observer(shell()->web_contents());
controller.GoBack();
back_load_observer.Wait();
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(blocked_url, controller.GetLastCommittedEntry()->GetURL());
EXPECT_EQ(blocked_url, controller.GetLastCommittedEntry()->GetVirtualURL());
}
#if BUILDFLAG(IS_LINUX)
#define MAYBE_JavascriptRedirectSilentlyCanceled \
DISABLED_JavascriptRedirectSilentlyCanceled
#else
#define MAYBE_JavascriptRedirectSilentlyCanceled \
JavascriptRedirectSilentlyCanceled
#endif
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
MAYBE_JavascriptRedirectSilentlyCanceled) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
GURL redirect_to_unsafe_url(
embedded_test_server()->GetURL("/server-redirect?javascript:Hello!"));
EXPECT_FALSE(NavigateToURL(shell(), redirect_to_unsafe_url));
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(PAGE_TYPE_NORMAL,
controller.GetLastCommittedEntry()->GetPageType());
EXPECT_EQ(controller.GetVisibleEntry(), controller.GetLastCommittedEntry());
EXPECT_EQ(start_url, controller.GetVisibleEntry()->GetURL());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
PreventSpoofFromBlockedRedirect) {
GURL url1 = embedded_test_server()->GetURL(
"a.com", "/navigation_controller/simple_page_1.html");
EXPECT_TRUE(NavigateToURL(shell(), url1));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ShellAddedObserver new_shell_observer;
EXPECT_TRUE(ExecJs(root, "var w = window.open()"));
Shell* new_shell = new_shell_observer.GetShell();
ASSERT_NE(new_shell->web_contents(), shell()->web_contents());
GURL redirect_to_data_url(
embedded_test_server()->GetURL("/server-redirect?data:text/html,Hello!"));
TestNavigationObserver nav_observer(new_shell->web_contents(), 1);
EXPECT_TRUE(
ExecJs(root, "w.location.href = '" + redirect_to_data_url.spec() + "';"));
nav_observer.WaitForNavigationFinished();
EXPECT_FALSE(nav_observer.last_navigation_succeeded());
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
new_shell->web_contents()->GetController());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(redirect_to_data_url, controller.GetLastCommittedEntry()->GetURL());
EXPECT_EQ(PAGE_TYPE_ERROR, controller.GetLastCommittedEntry()->GetPageType());
EXPECT_TRUE(NavigateToURL(new_shell, url1));
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(url1, controller.GetLastCommittedEntry()->GetURL());
TestNavigationObserver back_load_observer(new_shell->web_contents());
controller.GoBack();
back_load_observer.Wait();
EXPECT_EQ(redirect_to_data_url, controller.GetLastCommittedEntry()->GetURL());
std::string result = EvalJs(shell(),
"try {\n"
" w.document.body.innerHTML;\n"
"} catch (e) {\n"
" e.toString();\n"
"}")
.ExtractString();
DLOG(INFO) << "Result: " << result;
EXPECT_THAT(result,
::testing::MatchesRegex("SecurityError: Blocked a frame with "
"origin \"http://a.com:\\d+\" from "
"accessing a cross-origin frame."));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
SameDocumentNavAfterJavaScriptURL) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(200, contents()->GetPrimaryMainFrame()->last_http_status_code());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
const int64_t start_dsn = controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number();
EXPECT_TRUE(ExecJs(root, R"(window.location = 'javascript:"foo"';)"));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(start_url, root->current_url());
EXPECT_EQ("foo", EvalJs(shell(), "document.body.innerHTML"));
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(200, contents()->GetPrimaryMainFrame()->last_http_status_code());
EXPECT_EQ(start_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number());
GURL fragment_url = embedded_test_server()->GetURL("/title1.html#bar");
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "location.href='#bar';"));
capturer.Wait();
EXPECT_NE(start_url, root->current_url());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(200, contents()->GetPrimaryMainFrame()->last_http_status_code());
EXPECT_EQ(start_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number());
}
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "history.go(-1);"));
capturer.Wait();
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(start_url, root->current_url());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(200, contents()->GetPrimaryMainFrame()->last_http_status_code());
EXPECT_EQ(start_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
BrowserInitiatedSameDocumentNavAfterJavaScriptURL) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(200, contents()->GetPrimaryMainFrame()->last_http_status_code());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
const int64_t start_dsn = controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number();
EXPECT_TRUE(ExecJs(root, R"(window.location = 'javascript:"foo"';)"));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(start_url, root->current_url());
EXPECT_EQ("foo", EvalJs(shell(), "document.body.innerHTML"));
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(200, contents()->GetPrimaryMainFrame()->last_http_status_code());
EXPECT_EQ(start_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number());
GURL fragment_url = embedded_test_server()->GetURL("/title1.html#bar");
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(NavigateToURL(shell(), fragment_url));
capturer.Wait();
EXPECT_EQ(fragment_url, root->current_url());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(200, contents()->GetPrimaryMainFrame()->last_http_status_code());
EXPECT_EQ(start_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number());
}
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "history.go(-1);"));
capturer.Wait();
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(start_url, root->current_url());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(200, contents()->GetPrimaryMainFrame()->last_http_status_code());
EXPECT_EQ(start_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
SameDocumentNavAfterDocumentReplaceChild) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL main_url(embedded_test_server()->GetURL("/page_with_iframe.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(200, contents()->GetPrimaryMainFrame()->last_http_status_code());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
FrameTreeNode* iframe = root->child_at(0);
const int64_t start_dsn = controller.GetLastCommittedEntry()
->GetFrameEntry(iframe)
->document_sequence_number();
GURL iframe_url = iframe->current_url();
EXPECT_TRUE(ExecJs(root, R"(
let newDoc = document.implementation.createHTMLDocument();
newDoc.body.innerHTML = "foo";
let frame = document.getElementById("test_iframe");
let destDocument = frame.contentDocument;
let newNode = destDocument.importNode(newDoc.documentElement, true);
destDocument.replaceChild(newNode, destDocument.documentElement);
)"));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(iframe_url, iframe->current_url());
EXPECT_EQ("foo", EvalJs(iframe, "document.body.innerHTML"));
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(200, contents()->GetPrimaryMainFrame()->last_http_status_code());
EXPECT_EQ(start_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(iframe)
->document_sequence_number());
GURL fragment_url = embedded_test_server()->GetURL("/title1.html#bar");
{
FrameNavigateParamsCapturer capturer(iframe);
EXPECT_TRUE(ExecJs(iframe, "location.href='#bar';"));
capturer.Wait();
EXPECT_EQ(iframe_url.spec() + "#bar", iframe->current_url().spec());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(200, contents()->GetPrimaryMainFrame()->last_http_status_code());
EXPECT_EQ(start_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(iframe)
->document_sequence_number());
}
{
FrameNavigateParamsCapturer capturer(iframe);
EXPECT_TRUE(ExecJs(iframe, "history.go(-1);"));
capturer.Wait();
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(iframe_url, iframe->current_url());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(200, contents()->GetPrimaryMainFrame()->last_http_status_code());
EXPECT_EQ(start_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(iframe)
->document_sequence_number());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
SameDocumentNavAfterXSL) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL start_url(embedded_test_server()->GetURL("/permissions-policy.xml"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(200, contents()->GetPrimaryMainFrame()->last_http_status_code());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
const int64_t start_dsn = controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number();
EXPECT_TRUE(WaitForLoadStop(contents()));
GURL fragment_url =
embedded_test_server()->GetURL("/permissions-policy.xml#bar");
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(NavigateToURL(shell(), fragment_url));
capturer.Wait();
EXPECT_EQ(fragment_url, root->current_url());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(200, contents()->GetPrimaryMainFrame()->last_http_status_code());
EXPECT_EQ(start_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number());
}
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "history.go(-1);"));
capturer.Wait();
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(start_url, root->current_url());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(200, contents()->GetPrimaryMainFrame()->last_http_status_code());
EXPECT_EQ(start_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
SameDocumentNavAfterJavaScriptURLOn404Page) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL start_url(embedded_test_server()->GetURL("/page404.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(404, contents()->GetPrimaryMainFrame()->last_http_status_code());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
const int64_t start_dsn = controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number();
EXPECT_TRUE(ExecJs(root, R"(window.location = 'javascript:"foo"';)"));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(start_url, root->current_url());
EXPECT_EQ("foo", EvalJs(shell(), "document.body.innerHTML"));
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(404, contents()->GetPrimaryMainFrame()->last_http_status_code());
EXPECT_EQ(start_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number());
GURL fragment_url = embedded_test_server()->GetURL("/page404.html#bar");
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "location.href='#bar';"));
capturer.Wait();
EXPECT_NE(start_url, root->current_url());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(404, contents()->GetPrimaryMainFrame()->last_http_status_code());
EXPECT_EQ(start_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number());
}
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "history.go(-1);"));
capturer.Wait();
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(start_url, root->current_url());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(404, contents()->GetPrimaryMainFrame()->last_http_status_code());
EXPECT_EQ(start_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
BackSameDocumentAfterBlockedSubframe) {
DisableBackForwardCacheForTesting(shell()->web_contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL start_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe_simple.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL original_child_url = root->child_at(0)->current_url();
GURL x_frame_options_deny_url =
embedded_test_server()->GetURL("/x-frame-options-deny.html");
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
std::string pushStateToXfo =
"history.pushState({}, '', '/x-frame-options-deny.html')";
EXPECT_TRUE(ExecJs(root->child_at(0), pushStateToXfo));
capturer.Wait();
EXPECT_EQ(x_frame_options_deny_url, root->child_at(0)->current_url());
EXPECT_TRUE(capturer.is_same_document());
}
GURL new_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), new_url));
{
TestNavigationObserver observer(shell()->web_contents());
controller.GoBack();
observer.Wait();
EXPECT_EQ(start_url, root->current_url());
EXPECT_EQ(x_frame_options_deny_url, root->child_at(0)->current_url());
EXPECT_EQ(net::ERR_BLOCKED_BY_RESPONSE, observer.last_net_error_code());
EXPECT_FALSE(observer.last_navigation_succeeded());
}
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
TestNavigationObserver observer(shell()->web_contents());
controller.GoBack();
capturer.Wait();
observer.Wait();
EXPECT_FALSE(capturer.is_same_document());
EXPECT_EQ(start_url, root->current_url());
EXPECT_EQ(original_child_url, root->child_at(0)->current_url());
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(net::OK, observer.last_net_error_code());
}
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "history.go(2)"));
capturer.Wait();
EXPECT_EQ(new_url, root->current_url());
EXPECT_FALSE(capturer.is_same_document());
}
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "history.go(-2)"));
capturer.Wait();
EXPECT_EQ(start_url, root->current_url());
EXPECT_EQ(original_child_url, root->child_at(0)->current_url());
EXPECT_FALSE(capturer.is_same_document());
}
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
TestNavigationObserver observer(shell()->web_contents());
controller.GoForward();
capturer.Wait();
observer.Wait();
EXPECT_EQ(start_url, root->current_url());
EXPECT_EQ(x_frame_options_deny_url, root->child_at(0)->current_url());
if (!SiteIsolationPolicy::IsErrorPageIsolationEnabled(
false)) {
EXPECT_TRUE(capturer.is_same_document());
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(net::OK, observer.last_net_error_code());
} else {
EXPECT_FALSE(capturer.is_same_document());
EXPECT_FALSE(observer.last_navigation_succeeded());
EXPECT_EQ(net::ERR_BLOCKED_BY_RESPONSE, observer.last_net_error_code());
}
}
EXPECT_TRUE(ExecJs(root->child_at(0), "console.log('Success');"));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
BackSameDocumentAfter404MainFrame) {
DisableBackForwardCacheForTesting(shell()->web_contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL error_url = embedded_test_server()->GetURL("/empty404.html");
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "history.pushState({}, '', '/empty404.html')"));
capturer.Wait();
EXPECT_EQ(error_url, root->current_url());
EXPECT_TRUE(capturer.is_same_document());
}
GURL new_url(embedded_test_server()->GetURL("/title2.html"));
EXPECT_TRUE(NavigateToURL(shell(), new_url));
{
TestNavigationObserver observer(shell()->web_contents());
controller.GoBack();
observer.Wait();
EXPECT_EQ(error_url, root->current_url());
EXPECT_EQ(net::ERR_HTTP_RESPONSE_CODE_FAILURE,
observer.last_net_error_code());
EXPECT_FALSE(observer.last_navigation_succeeded());
}
{
FrameNavigateParamsCapturer capturer(root);
TestNavigationObserver observer(shell()->web_contents());
controller.GoBack();
capturer.Wait();
observer.Wait();
EXPECT_EQ(start_url, root->current_url());
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(net::OK, observer.last_net_error_code());
EXPECT_FALSE(capturer.is_same_document());
}
EXPECT_TRUE(ExecJs(root, "console.log('Success');"));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
HistoryAPIHistoryNavigation) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
const int64_t start_dsn = controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number();
GURL push_state_url(embedded_test_server()->GetURL("/title2.html"));
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "history.pushState({}, '', '/title2.html')"));
capturer.Wait();
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ(start_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number());
}
GURL end_url(embedded_test_server()->GetURL("/title3.html"));
EXPECT_TRUE(NavigateToURL(shell(), end_url));
EXPECT_NE(start_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number());
{
FrameNavigateParamsCapturer capturer(root);
TestNavigationObserver observer(shell()->web_contents());
controller.GoBack();
capturer.Wait();
observer.Wait();
EXPECT_FALSE(capturer.is_same_document());
EXPECT_EQ(push_state_url, root->current_url());
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(start_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number());
EXPECT_TRUE(ExecJs(shell(), "var foo = 42;"));
}
{
FrameNavigateParamsCapturer capturer(root);
TestNavigationObserver observer(shell()->web_contents());
controller.GoBack();
capturer.Wait();
observer.Wait();
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ(start_url, root->current_url());
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(start_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number());
EXPECT_EQ(42, EvalJs(shell(), "foo"));
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
GoBackToManualSubFrame) {
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(1U, root->child_count());
ASSERT_NE(nullptr, root->child_at(0));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
EXPECT_EQ(1, controller.GetEntryCount());
{
LoadCommittedCapturer capturer(root->child_at(0));
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
NavigateFrameToURL(root->child_at(0), frame_url);
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition_type(), ui::PAGE_TRANSITION_AUTO_SUBFRAME));
EXPECT_EQ(1, controller.GetEntryCount());
}
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
GURL frame_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
NavigateFrameToURL(root->child_at(0), frame_url);
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME));
EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.navigation_type());
EXPECT_EQ(2, controller.GetEntryCount());
}
{
FrameNavigateParamsCapturer capturer(root);
GURL main_url_2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
NavigateFrameToURL(root, main_url_2);
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(), ui::PAGE_TRANSITION_LINK));
EXPECT_EQ(3, controller.GetEntryCount());
}
{
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
controller.GetEntryAtIndex(0)->GetTransitionType(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
controller.GetEntryAtIndex(1)->GetTransitionType(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
controller.GetEntryAtIndex(2)->GetTransitionType(),
ui::PAGE_TRANSITION_LINK));
}
{
FrameNavigateParamsCapturer capturer(root);
shell()->web_contents()->GetController().GoBack();
capturer.Wait();
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
capturer.transition(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FORWARD_BACK |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
}
{
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
controller.GetEntryAtIndex(0)->GetTransitionType(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
controller.GetEntryAtIndex(1)->GetTransitionType(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FORWARD_BACK |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)));
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
controller.GetEntryAtIndex(2)->GetTransitionType(),
ui::PAGE_TRANSITION_LINK));
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
GoBackFromCrossSiteSubFrame) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL initial_subframe_url =
root->child_at(0)->current_frame_host()->GetLastCommittedURL();
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetCurrentEntryIndex());
GURL final_subframe_url =
embedded_test_server()->GetURL("b.com", "/title1.html");
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), final_subframe_url));
EXPECT_EQ(final_subframe_url,
root->child_at(0)->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
TestNavigationObserver nav_observer(shell()->web_contents(), 1);
EXPECT_TRUE(ExecJs(root->child_at(0), "history.back()"));
nav_observer.Wait();
EXPECT_EQ(initial_subframe_url,
root->child_at(0)->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetCurrentEntryIndex());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
HashNavigationVsBeforeUnloadEvent) {
GURL main_url(embedded_test_server()->GetURL("/title1.html"));
GURL hash_url(embedded_test_server()->GetURL("/title1.html#hash"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
EXPECT_TRUE(ExecJs(shell(),
R"( window.addEventListener("beforeunload", function(e) {
domAutomationController.send("beforeunload");
});
window.addEventListener("unload", function(e) {
domAutomationController.send("unload");
});
)"));
DOMMessageQueue message_queue(shell()->web_contents());
std::vector<std::string> messages;
std::string message;
EXPECT_TRUE(NavigateToURL(shell(), hash_url));
while (message_queue.PopMessage(&message))
messages.push_back(message);
EXPECT_THAT(messages, testing::IsEmpty());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
PruningOfEntriesForDynamicFrames_ChildRemoved) {
GURL main_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
std::string script = R"(
(async () => {
for (let i = 0; i < 5; i++) {
// Create and remove an iframe.
let iframe = document.createElement('iframe');
document.body.appendChild(iframe);
document.body.removeChild(iframe);
// Let the message loop run (this works in an async function).
await new Promise(resolve => setTimeout(resolve, 0));
}
return 'done-with-test';
})(); )";
EXPECT_EQ("done-with-test", EvalJs(shell(), script));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(main_url, entry->GetURL());
EXPECT_EQ(0U, entry->root_node()->children.size());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(0U, root->child_count());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
PruningOfEntriesForDynamicFrames_ParentNavigatedAway) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/navigation_controller/page_with_iframe_simple.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
RenderFrameHost* frame = ChildFrameAt(current_main_frame_host(), 0);
std::string script = R"(
for (var i = 0; i < 5; i++) {
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
}; )";
EXPECT_TRUE(ExecJs(frame, script));
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(main_url, entry->GetURL());
EXPECT_EQ(1U, entry->root_node()->children.size());
EXPECT_EQ(5U, entry->root_node()->children[0]->children.size());
GURL next_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "frame", next_url));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(main_url, entry->GetURL());
EXPECT_EQ(1U, entry->root_node()->children.size());
EXPECT_EQ(0U, entry->root_node()->children[0]->children.size());
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
PruningOfEntriesForDynamicFrames_MainFrameNavigatedAway) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/navigation_controller/page_with_iframe_simple.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
RenderFrameHost* frame = ChildFrameAt(current_main_frame_host(), 0);
std::string script = R"(
for (var i = 0; i < 5; i++) {
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
}; )";
EXPECT_TRUE(ExecJs(frame, script));
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(main_url, entry->GetURL());
EXPECT_EQ(1U, entry->root_node()->children.size());
EXPECT_EQ(5U, entry->root_node()->children[0]->children.size());
GURL next_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
EXPECT_TRUE(NavigateToURL(shell(), next_url));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(main_url, entry->GetURL());
EXPECT_EQ(1U, entry->root_node()->children.size());
EXPECT_EQ(0U, entry->root_node()->children[0]->children.size());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
UtilizationOfSpareRenderProcessHost) {
GURL first_url = embedded_test_server()->GetURL("a.com", "/title1.html");
GURL second_url = embedded_test_server()->GetURL("b.com", "/title2.html");
RenderProcessHost* prev_spare = nullptr;
RenderProcessHost* curr_spare = nullptr;
RenderProcessHost* prev_host = nullptr;
RenderProcessHost* curr_host = nullptr;
curr_spare = RenderProcessHostImpl::GetSpareRenderProcessHostForTesting();
curr_host = shell()->web_contents()->GetPrimaryMainFrame()->GetProcess();
EXPECT_FALSE(curr_spare);
prev_host = curr_host;
prev_spare = curr_spare;
EXPECT_TRUE(NavigateToURL(shell(), first_url));
curr_spare = RenderProcessHostImpl::GetSpareRenderProcessHostForTesting();
curr_host = shell()->web_contents()->GetPrimaryMainFrame()->GetProcess();
EXPECT_NE(curr_spare, curr_host);
EXPECT_EQ(prev_host, curr_host);
if (AreAllSitesIsolatedForTesting())
EXPECT_TRUE(curr_spare);
prev_host = curr_host;
prev_spare = curr_spare;
DisableBackForwardCacheForTesting(contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
RenderProcessHostWatcher prev_host_watcher(
prev_host, RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
EXPECT_TRUE(NavigateToURL(shell(), second_url));
prev_host_watcher.Wait();
curr_spare = RenderProcessHostImpl::GetSpareRenderProcessHostForTesting();
curr_host = shell()->web_contents()->GetPrimaryMainFrame()->GetProcess();
EXPECT_NE(prev_host, curr_host);
if (prev_spare)
EXPECT_EQ(prev_spare, curr_host);
if (AreAllSitesIsolatedForTesting()) {
EXPECT_TRUE(curr_spare);
EXPECT_NE(prev_spare, curr_spare);
}
prev_host = curr_host;
prev_spare = curr_spare;
TestNavigationObserver back_load_observer(shell()->web_contents());
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
controller.GoBack();
back_load_observer.Wait();
curr_spare = RenderProcessHostImpl::GetSpareRenderProcessHostForTesting();
curr_host = shell()->web_contents()->GetPrimaryMainFrame()->GetProcess();
EXPECT_NE(prev_host, curr_host);
if (prev_spare)
EXPECT_EQ(prev_spare, curr_host);
if (AreAllSitesIsolatedForTesting()) {
EXPECT_TRUE(curr_spare);
EXPECT_NE(prev_spare, curr_spare);
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
DataURLSameDocumentNavigation) {
GURL url_first("data:text/html,body#foo");
GURL url_second("data:text/html,body#bar");
EXPECT_TRUE(url_first.EqualsIgnoringRef(url_second));
EXPECT_TRUE(NavigateToURL(shell(), url_first));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
FrameNavigateParamsCapturer capturer(root);
shell()->LoadURL(url_second);
capturer.Wait();
EXPECT_TRUE(capturer.is_same_document());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
EmptyBody404CommitsErrorPage) {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
GURL url(embedded_test_server()->GetURL("/empty404.html"));
{
TestNavigationObserverInternal observer(contents());
shell()->LoadURL(url);
observer.Wait();
EXPECT_FALSE(observer.last_navigation_succeeded());
EXPECT_EQ(net::ERR_HTTP_RESPONSE_CODE_FAILURE,
observer.last_net_error_code());
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY,
observer.last_navigation_type());
EXPECT_EQ(PAGE_TYPE_ERROR,
controller.GetLastCommittedEntry()->GetPageType());
EXPECT_EQ(true,
EvalJs(contents(), "document.body.innerText.includes('404')"));
}
{
TestNavigationObserverInternal reload_observer(contents());
shell()->Reload();
reload_observer.Wait();
EXPECT_FALSE(reload_observer.last_navigation_succeeded());
EXPECT_EQ(net::ERR_HTTP_RESPONSE_CODE_FAILURE,
reload_observer.last_net_error_code());
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
reload_observer.last_navigation_type());
EXPECT_EQ(PAGE_TYPE_ERROR,
controller.GetLastCommittedEntry()->GetPageType());
}
{
TestNavigationObserverInternal same_url_observer(contents());
controller.LoadURL(url, Referrer(), ui::PAGE_TRANSITION_TYPED,
std::string() );
same_url_observer.Wait();
EXPECT_FALSE(same_url_observer.last_navigation_succeeded());
EXPECT_EQ(net::ERR_HTTP_RESPONSE_CODE_FAILURE,
same_url_observer.last_net_error_code());
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY,
same_url_observer.last_navigation_type());
EXPECT_EQ(PAGE_TYPE_ERROR,
controller.GetLastCommittedEntry()->GetPageType());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTestNoServer,
EmptyBody500CommitsErrorPage) {
net::test_server::ControllableHttpResponse response(embedded_test_server(),
"/title1.html");
ASSERT_TRUE(embedded_test_server()->Start());
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
GURL url(embedded_test_server()->GetURL("/title1.html"));
TestNavigationObserver observer(contents());
shell()->LoadURL(url);
response.WaitForRequest();
response.Send(net::HTTP_INTERNAL_SERVER_ERROR);
response.Done();
observer.Wait();
EXPECT_FALSE(observer.last_navigation_succeeded());
EXPECT_EQ(net::ERR_HTTP_RESPONSE_CODE_FAILURE,
observer.last_net_error_code());
EXPECT_EQ(PAGE_TYPE_ERROR, controller.GetLastCommittedEntry()->GetPageType());
EXPECT_EQ(true,
EvalJs(contents(), "document.body.innerText.includes('500')"));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
NonEmpty404BodyDoesNotCommitErrorPage) {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
GURL url(embedded_test_server()->GetURL("/page404.html"));
TestNavigationObserver observer(contents());
EXPECT_TRUE(NavigateToURL(shell(), url));
observer.WaitForNavigationFinished();
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(net::OK, observer.last_net_error_code());
EXPECT_EQ(PAGE_TYPE_NORMAL,
controller.GetLastCommittedEntry()->GetPageType());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
ErrorPageNavigationWithoutNavigationRequestGetsKilled) {
GURL good_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), good_url));
GURL bad_url(embedded_test_server()->GetURL("/title2.html"));
auto params = mojom::DidCommitProvisionalLoadParams::New();
params->did_create_new_entry = true;
params->url = bad_url;
params->referrer = blink::mojom::Referrer::New();
params->transition = ui::PAGE_TRANSITION_LINK;
params->page_state = blink::PageState::CreateFromURL(bad_url);
params->method = "POST";
params->post_id = 2;
params->url_is_unreachable = true;
params->embedding_token = base::UnguessableToken::Create();
RenderFrameHostImpl* rfh = contents()->GetPrimaryMainFrame();
RenderProcessHostBadIpcMessageWaiter kill_waiter(rfh->GetProcess());
static_cast<mojom::FrameHost*>(rfh)->DidCommitProvisionalLoad(
std::move(params),
mojom::DidCommitProvisionalLoadInterfaceParams::New(
mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>()
.InitWithNewPipeAndPassReceiver()));
EXPECT_EQ(bad_message::RFH_NO_MATCHING_NAVIGATION_REQUEST_ON_COMMIT,
kill_waiter.Wait());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
LoadURL_SamePage_DifferentMethod) {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
GURL form_submit_url(embedded_test_server()->GetURL("/title2.html"));
CreateAndSubmitForm(form_submit_url);
EXPECT_TRUE(NavigateToURL(shell(), form_submit_url));
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(form_submit_url, entry->GetURL());
EXPECT_FALSE(entry->GetHasPostData());
EXPECT_EQ(entry->GetPostID(), -1);
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
LoadURL_SamePage_DifferentMethod_RendererInitiated) {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
GURL form_submit_url(embedded_test_server()->GetURL("/title2.html"));
CreateAndSubmitForm(form_submit_url);
EXPECT_TRUE(NavigateToURLFromRenderer(shell(), form_submit_url));
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(form_submit_url, entry->GetURL());
EXPECT_FALSE(entry->GetHasPostData());
EXPECT_EQ(entry->GetPostID(), -1);
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FormSubmissionToNewTab) {
GURL url_start(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_start));
WebContentsAddedObserver web_contents_added_observer;
TestNavigationObserver navigation_observer(nullptr, 1);
navigation_observer.StartWatchingNewWebContents();
ASSERT_TRUE(ExecuteScript(contents(),
R"(let form = document.createElement('form');
form.method = 'POST';
form.target = '_blank';
form.action = 'about:blank';
document.body.appendChild(form);
form.submit();)"));
WebContentsImpl* popup_contents = static_cast<WebContentsImpl*>(
web_contents_added_observer.GetWebContents());
navigation_observer.WaitForNavigationFinished();
EXPECT_EQ(GURL(url::kAboutBlankURL), popup_contents->GetLastCommittedURL());
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(popup_contents->GetController());
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(GURL(url::kAboutBlankURL), entry->GetURL());
EXPECT_TRUE(entry->GetHasPostData());
EXPECT_NE(entry->GetPostID(), -1);
EXPECT_EQ("POST", popup_contents->GetPrimaryMainFrame()->last_http_method());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FormSubmitServerRedirect) {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
GURL url2(embedded_test_server()->GetURL("/title2.html"));
GURL redirect_to_url2_url(
embedded_test_server()->GetURL("/server-redirect?" + url2.spec()));
TestNavigationObserver form_nav_observer(contents());
EXPECT_TRUE(
ExecJs(contents(), JsReplace("var form = document.createElement('form');"
"form.method = 'POST';"
"form.action = $1;"
"document.body.appendChild(form);"
"form.submit();",
redirect_to_url2_url)));
form_nav_observer.Wait();
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(url2, entry->GetURL());
EXPECT_FALSE(entry->GetHasPostData());
EXPECT_EQ(-1, entry->GetPostID());
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
FormSubmitClientRedirect) {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
GURL url2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
GURL redirect_to_url2_url(embedded_test_server()->GetURL(
"/navigation_controller/client_redirect.html"));
TestNavigationObserver form_nav_observer(contents());
EXPECT_TRUE(
ExecJs(contents(), JsReplace("var form = document.createElement('form');"
"form.method = 'POST';"
"form.action = $1;"
"document.body.appendChild(form);"
"form.submit();",
redirect_to_url2_url)));
form_nav_observer.Wait();
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(url2, entry->GetURL());
EXPECT_FALSE(entry->GetHasPostData());
EXPECT_EQ(-1, entry->GetPostID());
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
}
class CountRepostFormWarningWebContentsDelegate : public WebContentsDelegate {
public:
CountRepostFormWarningWebContentsDelegate() = default;
int repost_form_warning_count() { return repost_form_warning_count_; }
void ShowRepostFormWarningDialog(WebContents* source) override {
repost_form_warning_count_++;
}
private:
int repost_form_warning_count_ = 0;
};
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
ResetPendingLoadTypeWhenCancelPendingReload) {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
auto delegate = std::make_unique<CountRepostFormWarningWebContentsDelegate>();
contents()->SetDelegate(delegate.get());
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
GURL form_submit_url(embedded_test_server()->GetURL("/title2.html"));
const int64_t form_post_id = CreateAndSubmitForm(form_submit_url);
EXPECT_EQ(0, delegate->repost_form_warning_count());
{
NavigationControllerImpl::ScopedShowRepostDialogForTesting show_repost;
controller.Reload(ReloadType::NORMAL, true );
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(form_submit_url, contents()->GetLastCommittedURL());
EXPECT_TRUE(controller.GetLastCommittedEntry()->GetHasPostData());
EXPECT_EQ(form_post_id, controller.GetLastCommittedEntry()->GetPostID());
}
EXPECT_EQ(ReloadType::NORMAL, controller.pending_reload_);
EXPECT_EQ(1, delegate->repost_form_warning_count());
const GURL url1(embedded_test_server()->GetURL("/title3.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
EXPECT_EQ(url1, contents()->GetLastCommittedURL());
EXPECT_EQ(ReloadType::NONE, controller.pending_reload_);
controller.ContinuePendingReload();
EXPECT_FALSE(controller.GetPendingEntry());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, PostThenReload) {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
auto delegate = std::make_unique<CountRepostFormWarningWebContentsDelegate>();
contents()->SetDelegate(delegate.get());
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
GURL form_submit_url(embedded_test_server()->GetURL("/title2.html"));
const int64_t form_post_id = CreateAndSubmitForm(form_submit_url);
EXPECT_EQ(0, delegate->repost_form_warning_count());
{
NavigationControllerImpl::ScopedShowRepostDialogForTesting show_repost;
controller.Reload(ReloadType::NORMAL, true );
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(form_submit_url, contents()->GetLastCommittedURL());
EXPECT_TRUE(controller.GetLastCommittedEntry()->GetHasPostData());
EXPECT_EQ(form_post_id, controller.GetLastCommittedEntry()->GetPostID());
}
EXPECT_EQ(1, delegate->repost_form_warning_count());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
PostThenReplaceStateThenReload) {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
auto delegate = std::make_unique<CountRepostFormWarningWebContentsDelegate>();
contents()->SetDelegate(delegate.get());
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
GURL form_submit_url(embedded_test_server()->GetURL("/title2.html"));
CreateAndSubmitForm(form_submit_url);
const int kExpectedRepostFormWarningCount = 0;
EXPECT_EQ(kExpectedRepostFormWarningCount,
delegate->repost_form_warning_count());
GURL replace_url(embedded_test_server()->GetURL("/title2.html#foo"));
{
EXPECT_TRUE(
ExecJs(contents(), "history.replaceState({}, '', 'title2.html#foo')"));
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(replace_url, contents()->GetLastCommittedURL());
EXPECT_FALSE(controller.GetLastCommittedEntry()->GetHasPostData());
EXPECT_EQ(-1, controller.GetLastCommittedEntry()->GetPostID());
}
EXPECT_EQ(kExpectedRepostFormWarningCount,
delegate->repost_form_warning_count());
{
NavigationControllerImpl::ScopedShowRepostDialogForTesting show_repost;
controller.Reload(ReloadType::NORMAL, true );
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(replace_url, contents()->GetLastCommittedURL());
EXPECT_FALSE(controller.GetLastCommittedEntry()->GetHasPostData());
EXPECT_EQ(-1, controller.GetLastCommittedEntry()->GetPostID());
}
EXPECT_EQ(kExpectedRepostFormWarningCount,
delegate->repost_form_warning_count());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
PostThenPushStateThenReloadThenHistory) {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
auto delegate = std::make_unique<CountRepostFormWarningWebContentsDelegate>();
contents()->SetDelegate(delegate.get());
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
GURL form_submit_url(embedded_test_server()->GetURL("/title2.html"));
CreateAndSubmitForm(form_submit_url);
const int kExpectedRepostFormWarningCount = 0;
EXPECT_EQ(kExpectedRepostFormWarningCount,
delegate->repost_form_warning_count());
EXPECT_EQ("POST", contents()->GetPrimaryMainFrame()->last_http_method());
GURL push_url(embedded_test_server()->GetURL("/title2.html#foo"));
{
EXPECT_TRUE(
ExecJs(contents(), "history.pushState({}, '', 'title2.html#foo')"));
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(push_url, contents()->GetLastCommittedURL());
EXPECT_FALSE(controller.GetLastCommittedEntry()->GetHasPostData());
EXPECT_EQ(-1, controller.GetLastCommittedEntry()->GetPostID());
EXPECT_EQ(kExpectedRepostFormWarningCount,
delegate->repost_form_warning_count());
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
}
{
NavigationControllerImpl::ScopedShowRepostDialogForTesting show_repost;
controller.Reload(ReloadType::NORMAL, true );
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(push_url, contents()->GetLastCommittedURL());
EXPECT_FALSE(controller.GetLastCommittedEntry()->GetHasPostData());
EXPECT_EQ(-1, controller.GetLastCommittedEntry()->GetPostID());
EXPECT_EQ(kExpectedRepostFormWarningCount,
delegate->repost_form_warning_count());
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
}
{
NavigationControllerImpl::ScopedShowRepostDialogForTesting show_repost;
TestNavigationObserver load_observer(shell()->web_contents());
controller.GoBack();
load_observer.Wait();
EXPECT_EQ(form_submit_url, contents()->GetLastCommittedURL());
EXPECT_FALSE(controller.GetLastCommittedEntry()->GetHasPostData());
EXPECT_EQ(-1, controller.GetLastCommittedEntry()->GetPostID());
EXPECT_EQ(kExpectedRepostFormWarningCount,
delegate->repost_form_warning_count());
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
}
{
NavigationControllerImpl::ScopedShowRepostDialogForTesting show_repost;
TestNavigationObserver load_observer(shell()->web_contents());
controller.GoForward();
load_observer.Wait();
EXPECT_EQ(push_url, contents()->GetLastCommittedURL());
EXPECT_FALSE(controller.GetLastCommittedEntry()->GetHasPostData());
EXPECT_EQ(-1, controller.GetLastCommittedEntry()->GetPostID());
EXPECT_EQ(kExpectedRepostFormWarningCount,
delegate->repost_form_warning_count());
EXPECT_EQ("GET", contents()->GetPrimaryMainFrame()->last_http_method());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
PostThenFragmentNavigationThenReloadThenHistory) {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
auto delegate = std::make_unique<CountRepostFormWarningWebContentsDelegate>();
contents()->SetDelegate(delegate.get());
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
GURL form_submit_url(embedded_test_server()->GetURL("/title2.html"));
const int64_t form_post_id = CreateAndSubmitForm(form_submit_url);
EXPECT_EQ(0, delegate->repost_form_warning_count());
GURL fragment_url(embedded_test_server()->GetURL("/title2.html#foo"));
{
EXPECT_TRUE(ExecJs(contents(), "location.href = '#foo'"));
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(fragment_url, contents()->GetLastCommittedURL());
EXPECT_TRUE(controller.GetLastCommittedEntry()->GetHasPostData());
EXPECT_EQ(form_post_id, controller.GetLastCommittedEntry()->GetPostID());
EXPECT_EQ(0, delegate->repost_form_warning_count());
EXPECT_EQ("POST", contents()->GetPrimaryMainFrame()->last_http_method());
}
{
NavigationControllerImpl::ScopedShowRepostDialogForTesting show_repost;
controller.Reload(ReloadType::NORMAL, true );
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(fragment_url, contents()->GetLastCommittedURL());
EXPECT_TRUE(controller.GetLastCommittedEntry()->GetHasPostData());
EXPECT_EQ(form_post_id, controller.GetLastCommittedEntry()->GetPostID());
EXPECT_EQ(1, delegate->repost_form_warning_count());
EXPECT_EQ("POST", contents()->GetPrimaryMainFrame()->last_http_method());
}
{
NavigationControllerImpl::ScopedShowRepostDialogForTesting show_repost;
TestNavigationObserver load_observer(shell()->web_contents());
controller.GoBack();
load_observer.Wait();
EXPECT_EQ(form_submit_url, contents()->GetLastCommittedURL());
EXPECT_TRUE(controller.GetLastCommittedEntry()->GetHasPostData());
EXPECT_EQ(form_post_id, controller.GetLastCommittedEntry()->GetPostID());
EXPECT_EQ(1, delegate->repost_form_warning_count());
EXPECT_EQ("POST", contents()->GetPrimaryMainFrame()->last_http_method());
}
{
NavigationControllerImpl::ScopedShowRepostDialogForTesting show_repost;
TestNavigationObserver load_observer(shell()->web_contents());
controller.GoForward();
load_observer.Wait();
EXPECT_EQ(fragment_url, contents()->GetLastCommittedURL());
EXPECT_TRUE(controller.GetLastCommittedEntry()->GetHasPostData());
EXPECT_EQ(form_post_id, controller.GetLastCommittedEntry()->GetPostID());
EXPECT_EQ(1, delegate->repost_form_warning_count());
EXPECT_EQ("POST", contents()->GetPrimaryMainFrame()->last_http_method());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
PostThenBrowserInitiatedFragmentNavigationThenReload) {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
auto delegate = std::make_unique<CountRepostFormWarningWebContentsDelegate>();
contents()->SetDelegate(delegate.get());
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
GURL form_submit_url(embedded_test_server()->GetURL("/title2.html"));
const int64_t form_post_id = CreateAndSubmitForm(form_submit_url);
EXPECT_EQ(0, delegate->repost_form_warning_count());
GURL fragment_url(embedded_test_server()->GetURL("/title2.html#foo"));
{
EXPECT_TRUE(NavigateToURL(shell(), fragment_url));
EXPECT_EQ(fragment_url, contents()->GetLastCommittedURL());
EXPECT_TRUE(controller.GetLastCommittedEntry()->GetHasPostData());
EXPECT_EQ(form_post_id, controller.GetLastCommittedEntry()->GetPostID());
EXPECT_EQ(0, delegate->repost_form_warning_count());
EXPECT_EQ("POST", contents()->GetPrimaryMainFrame()->last_http_method());
}
{
NavigationControllerImpl::ScopedShowRepostDialogForTesting show_repost;
controller.Reload(ReloadType::NORMAL, true );
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(fragment_url, contents()->GetLastCommittedURL());
EXPECT_TRUE(controller.GetLastCommittedEntry()->GetHasPostData());
EXPECT_EQ(form_post_id, controller.GetLastCommittedEntry()->GetPostID());
EXPECT_EQ(1, delegate->repost_form_warning_count());
EXPECT_EQ("POST", contents()->GetPrimaryMainFrame()->last_http_method());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
PostThenJavaScriptURLThenBrowserInitiatedFragment) {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
const int64_t start_dsn = controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number();
GURL form_submit_url(embedded_test_server()->GetURL("/title2.html"));
const int64_t form_post_id = CreateAndSubmitForm(form_submit_url);
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ("POST", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(200, contents()->GetPrimaryMainFrame()->last_http_status_code());
const int64_t form_dsn = controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number();
DCHECK_NE(start_dsn, form_dsn);
{
EXPECT_TRUE(ExecJs(root, R"(window.location = 'javascript:"foo"';)"));
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(form_submit_url, root->current_url());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ("foo", EvalJs(shell(), "document.body.innerHTML"));
EXPECT_TRUE(controller.GetLastCommittedEntry()->GetHasPostData());
EXPECT_EQ(form_post_id, controller.GetLastCommittedEntry()->GetPostID());
EXPECT_EQ("POST", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(200, contents()->GetPrimaryMainFrame()->last_http_status_code());
DCHECK_EQ(form_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number());
}
GURL fragment_url(embedded_test_server()->GetURL("/title2.html#foo"));
{
EXPECT_TRUE(NavigateToURL(shell(), fragment_url));
EXPECT_EQ(fragment_url, contents()->GetLastCommittedURL());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_TRUE(controller.GetLastCommittedEntry()->GetHasPostData());
EXPECT_EQ(form_post_id, controller.GetLastCommittedEntry()->GetPostID());
EXPECT_EQ("POST", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(200, contents()->GetPrimaryMainFrame()->last_http_status_code());
DCHECK_EQ(form_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
PostThenJavaScriptURLThenRendererInitiatedFragment) {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
const int64_t start_dsn = controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number();
GURL form_submit_url(embedded_test_server()->GetURL("/title2.html"));
const int64_t form_post_id = CreateAndSubmitForm(form_submit_url);
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ("POST", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(200, contents()->GetPrimaryMainFrame()->last_http_status_code());
const int64_t form_dsn = controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number();
DCHECK_NE(start_dsn, form_dsn);
{
EXPECT_TRUE(ExecJs(root, R"(window.location = 'javascript:"foo"';)"));
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(form_submit_url, root->current_url());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ("foo", EvalJs(shell(), "document.body.innerHTML"));
EXPECT_EQ("POST", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(200, contents()->GetPrimaryMainFrame()->last_http_status_code());
DCHECK_EQ(form_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number());
}
GURL fragment_url(embedded_test_server()->GetURL("/title2.html#foo"));
{
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "location.href='#foo';"));
capturer.Wait();
EXPECT_NE(start_url, root->current_url());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_TRUE(controller.GetLastCommittedEntry()->GetHasPostData());
EXPECT_EQ(form_post_id, controller.GetLastCommittedEntry()->GetPostID());
EXPECT_EQ("POST", contents()->GetPrimaryMainFrame()->last_http_method());
EXPECT_EQ(200, contents()->GetPrimaryMainFrame()->last_http_status_code());
DCHECK_EQ(form_dsn, controller.GetLastCommittedEntry()
->GetFrameEntry(root)
->document_sequence_number());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, PostSubframe) {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
auto delegate = std::make_unique<CountRepostFormWarningWebContentsDelegate>();
contents()->SetDelegate(delegate.get());
GURL start_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe_simple.html"));
GURL iframe_start_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
FrameTreeNode* iframe = root->child_at(0);
EXPECT_EQ(iframe_start_url,
iframe->current_frame_host()->GetLastCommittedURL());
GURL form_submit_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html#foo"));
{
FrameNavigateParamsCapturer capturer(root->child_at(0));
EXPECT_TRUE(
ExecJs(root, JsReplace(R"(var form = document.createElement('form');
form.method = 'POST';
form.action = $1;
form.target = 'simple_iframe';
document.body.appendChild(form);
form.submit();)",
form_submit_url)));
capturer.Wait();
EXPECT_EQ(form_submit_url,
iframe->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(0, delegate->repost_form_warning_count());
EXPECT_EQ("POST", iframe->current_frame_host()->last_http_method());
EXPECT_EQ("GET", root->current_frame_host()->last_http_method());
EXPECT_FALSE(controller.GetLastCommittedEntry()->GetHasPostData());
EXPECT_EQ(-1, controller.GetLastCommittedEntry()->GetPostID());
}
const int64_t form_post_id = iframe->current_frame_host()->last_post_id();
GURL fragment_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html#bar"));
{
NavigationControllerImpl::ScopedShowRepostDialogForTesting show_repost;
EXPECT_TRUE(ExecJs(iframe, "location.href = '#bar'"));
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(fragment_url,
iframe->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(0, delegate->repost_form_warning_count());
EXPECT_EQ("POST", iframe->current_frame_host()->last_http_method());
EXPECT_EQ(form_post_id, iframe->current_frame_host()->last_post_id());
EXPECT_EQ("GET", root->current_frame_host()->last_http_method());
EXPECT_FALSE(controller.GetLastCommittedEntry()->GetHasPostData());
EXPECT_EQ(-1, controller.GetLastCommittedEntry()->GetPostID());
}
{
NavigationControllerImpl::ScopedShowRepostDialogForTesting show_repost;
FrameNavigateParamsCapturer capturer(iframe);
EXPECT_TRUE(ExecJs(iframe, "location.reload();"));
capturer.Wait();
EXPECT_EQ(fragment_url,
iframe->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(0, delegate->repost_form_warning_count());
EXPECT_EQ("POST", iframe->current_frame_host()->last_http_method());
EXPECT_EQ(form_post_id, iframe->current_frame_host()->last_post_id());
}
{
NavigationControllerImpl::ScopedShowRepostDialogForTesting show_repost;
controller.Reload(ReloadType::NORMAL, true );
EXPECT_TRUE(WaitForLoadStop(contents()));
iframe = root->child_at(0);
EXPECT_EQ(iframe_start_url,
iframe->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(0, delegate->repost_form_warning_count());
EXPECT_EQ("GET", iframe->current_frame_host()->last_http_method());
EXPECT_EQ(-1, iframe->current_frame_host()->last_post_id());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
SiteInstanceChangeOnHistoryNavigation) {
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url2(embedded_test_server()->GetURL("b.com", "/title2.html"));
GURL url3(embedded_test_server()->GetURL("c.com", "/title3.html"));
GURL redirecting_url(embedded_test_server()->GetURL(
"a.com", "/server-redirect?" + url3.spec()));
EXPECT_TRUE(NavigateToURL(shell(), url1));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(url1, controller.GetEntryAtIndex(0)->GetURL());
scoped_refptr<SiteInstance> initial_site_instance =
root->current_frame_host()->GetSiteInstance();
{
FrameNavigateParamsCapturer capturer(root);
std::string script =
"history.replaceState({}, '', '" + redirecting_url.spec() + "')";
EXPECT_TRUE(ExecJs(root, script));
capturer.Wait();
}
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(redirecting_url, controller.GetEntryAtIndex(0)->GetURL());
EXPECT_EQ(initial_site_instance,
root->current_frame_host()->GetSiteInstance());
EXPECT_TRUE(NavigateToURL(shell(), url2));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
EXPECT_NE(initial_site_instance,
root->current_frame_host()->GetSiteInstance());
DisableBackForwardCacheForTesting(contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
FrameNavigateParamsCapturer capturer(root);
shell()->web_contents()->GetController().GoBack();
capturer.Wait();
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
NavigationEntry* entry = controller.GetEntryAtIndex(0);
EXPECT_EQ(entry, controller.GetLastCommittedEntry());
EXPECT_EQ(url3, entry->GetURL());
if (AreAllSitesIsolatedForTesting()) {
EXPECT_NE(initial_site_instance,
root->current_frame_host()->GetSiteInstance());
EXPECT_EQ(
SiteInfo::CreateForTesting(
IsolationContext(shell()->web_contents()->GetBrowserContext()),
url3),
root->current_frame_host()->GetSiteInstance()->GetSiteInfo());
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
} else {
EXPECT_EQ(initial_site_instance,
root->current_frame_host()->GetSiteInstance());
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
NoGestureInheritanceAfterCrossSiteNavigation_BrowserInitiated) {
GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url2(embedded_test_server()->GetURL("b.com", "/title2.html"));
GURL url3(embedded_test_server()->GetURL("c.com", "/title3.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
{
FrameNavigateParamsCapturer url2_capturer(root);
EXPECT_TRUE(NavigateToURLFromRenderer(shell(), url2));
url2_capturer.Wait();
EXPECT_TRUE(url2_capturer.has_user_gesture());
EXPECT_TRUE(root->current_frame_host()
->last_committed_common_params_has_user_gesture());
}
{
FrameNavigateParamsCapturer url3_capturer(root);
EXPECT_TRUE(NavigateToURL(shell(), url3));
url3_capturer.Wait();
EXPECT_FALSE(url3_capturer.has_user_gesture());
EXPECT_FALSE(root->current_frame_host()
->last_committed_common_params_has_user_gesture());
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
NoGestureInheritanceAfterCrossSiteNavigation_RendererInitiated) {
GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url2(embedded_test_server()->GetURL("b.com", "/title2.html"));
GURL url3(embedded_test_server()->GetURL("c.com", "/title3.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
{
FrameNavigateParamsCapturer url2_capturer(root);
EXPECT_TRUE(NavigateToURLFromRenderer(shell(), url2));
url2_capturer.Wait();
EXPECT_TRUE(url2_capturer.has_user_gesture());
EXPECT_TRUE(root->current_frame_host()
->last_committed_common_params_has_user_gesture());
}
{
FrameNavigateParamsCapturer url3_capturer(root);
EXPECT_TRUE(NavigateToURLFromRendererWithoutUserGesture(shell(), url3));
url3_capturer.Wait();
EXPECT_FALSE(url3_capturer.has_user_gesture());
EXPECT_FALSE(root->current_frame_host()
->last_committed_common_params_has_user_gesture());
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
NoGestureInheritanceAfterSameSiteNavigation_BrowserInitiated) {
GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url2(embedded_test_server()->GetURL("a.com", "/title2.html"));
GURL url3(embedded_test_server()->GetURL("a.com", "/title3.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
{
FrameNavigateParamsCapturer url2_capturer(root);
EXPECT_TRUE(NavigateToURLFromRenderer(shell(), url2));
url2_capturer.Wait();
EXPECT_TRUE(url2_capturer.has_user_gesture());
EXPECT_TRUE(root->current_frame_host()
->last_committed_common_params_has_user_gesture());
}
{
FrameNavigateParamsCapturer url3_capturer(root);
EXPECT_TRUE(NavigateToURL(shell(), url3));
url3_capturer.Wait();
EXPECT_FALSE(url3_capturer.has_user_gesture());
EXPECT_FALSE(root->current_frame_host()
->last_committed_common_params_has_user_gesture());
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
NoGestureInheritanceAfterSameSiteNavigation_RendererInitiated) {
GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url2(embedded_test_server()->GetURL("a.com", "/title2.html"));
GURL url3(embedded_test_server()->GetURL("a.com", "/title3.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
{
FrameNavigateParamsCapturer url2_capturer(root);
EXPECT_TRUE(NavigateToURLFromRenderer(shell(), url2));
url2_capturer.Wait();
EXPECT_TRUE(url2_capturer.has_user_gesture());
EXPECT_TRUE(root->current_frame_host()
->last_committed_common_params_has_user_gesture());
}
{
FrameNavigateParamsCapturer url3_capturer(root);
EXPECT_TRUE(NavigateToURLFromRendererWithoutUserGesture(shell(), url3));
url3_capturer.Wait();
EXPECT_FALSE(url3_capturer.has_user_gesture());
EXPECT_FALSE(root->current_frame_host()
->last_committed_common_params_has_user_gesture());
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
GestureChangesAfterSameDocumentNavOnDocumentLoadedWithoutGesture) {
GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url2(embedded_test_server()->GetURL("a.com", "/title1.html#a"));
GURL url3(embedded_test_server()->GetURL("a.com", "/title1.html#b"));
GURL url4(embedded_test_server()->GetURL("a.com", "/title1.html#c"));
GURL url5(embedded_test_server()->GetURL("a.com", "/title1.html#d"));
WebContentsImpl* contents =
static_cast<WebContentsImpl*>(shell()->web_contents());
FrameTreeNode* root = contents->GetPrimaryFrameTree().root();
{
FrameNavigateParamsCapturer url1_capturer(root);
EXPECT_TRUE(NavigateToURL(shell(), url1));
url1_capturer.Wait();
EXPECT_FALSE(url1_capturer.has_user_gesture());
EXPECT_FALSE(root->current_frame_host()
->last_committed_common_params_has_user_gesture());
}
{
FrameNavigateParamsCapturer url2_capturer(root);
EXPECT_TRUE(NavigateToURLFromRendererWithoutUserGesture(shell(), url2));
url2_capturer.Wait();
EXPECT_FALSE(url2_capturer.has_user_gesture());
EXPECT_FALSE(root->current_frame_host()
->last_committed_common_params_has_user_gesture());
}
{
FrameNavigateParamsCapturer url3_capturer(root);
EXPECT_TRUE(NavigateToURLFromRenderer(shell(), url3));
url3_capturer.Wait();
EXPECT_TRUE(url3_capturer.has_user_gesture());
EXPECT_TRUE(root->current_frame_host()
->last_committed_common_params_has_user_gesture());
}
{
FrameNavigateParamsCapturer url4_capturer(root);
EXPECT_TRUE(NavigateToURL(shell(), url4));
url4_capturer.Wait();
EXPECT_FALSE(url4_capturer.has_user_gesture());
EXPECT_FALSE(root->current_frame_host()
->last_committed_common_params_has_user_gesture());
}
{
FrameNavigateParamsCapturer url5_capturer(root);
TestNavigationObserver navigation_observer(contents);
NavigationController::LoadURLParams params(url5);
params.transition_type = ui::PageTransitionFromInt(
ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
params.has_user_gesture = true;
contents->GetController().LoadURLWithParams(params);
navigation_observer.Wait();
EXPECT_TRUE(navigation_observer.last_navigation_succeeded());
url5_capturer.Wait();
EXPECT_TRUE(url5_capturer.has_user_gesture());
EXPECT_TRUE(root->current_frame_host()
->last_committed_common_params_has_user_gesture());
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
GestureChangesAfterSameDocumentNavOnDocumentLoadedWithGesture) {
GURL url0(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url0));
WebContentsImpl* contents =
static_cast<WebContentsImpl*>(shell()->web_contents());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL url1(embedded_test_server()->GetURL("a.com", "/title2.html"));
GURL url2(embedded_test_server()->GetURL("a.com", "/title2.html#foo"));
GURL url3(embedded_test_server()->GetURL("a.com", "/title2.html#bar"));
GURL url4(embedded_test_server()->GetURL("a.com", "/title2.html#baz"));
{
FrameNavigateParamsCapturer url1_capturer(root);
EXPECT_TRUE(NavigateToURLFromRenderer(shell(), url1));
url1_capturer.Wait();
EXPECT_TRUE(url1_capturer.has_user_gesture());
EXPECT_TRUE(root->current_frame_host()
->last_committed_common_params_has_user_gesture());
}
{
FrameNavigateParamsCapturer url2_capturer(root);
EXPECT_TRUE(NavigateToURLFromRendererWithoutUserGesture(shell(), url2));
url2_capturer.Wait();
EXPECT_FALSE(url2_capturer.has_user_gesture());
EXPECT_FALSE(root->current_frame_host()
->last_committed_common_params_has_user_gesture());
}
{
FrameNavigateParamsCapturer url3_capturer(root);
EXPECT_TRUE(NavigateToURL(shell(), url3));
url3_capturer.Wait();
EXPECT_FALSE(url3_capturer.has_user_gesture());
EXPECT_FALSE(root->current_frame_host()
->last_committed_common_params_has_user_gesture());
}
{
FrameNavigateParamsCapturer url4_capturer(root);
TestNavigationObserver navigation_observer(contents);
NavigationController::LoadURLParams params(url4);
params.transition_type = ui::PageTransitionFromInt(
ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
params.has_user_gesture = true;
contents->GetController().LoadURLWithParams(params);
navigation_observer.Wait();
EXPECT_TRUE(navigation_observer.last_navigation_succeeded());
url4_capturer.Wait();
EXPECT_TRUE(url4_capturer.has_user_gesture());
EXPECT_TRUE(root->current_frame_host()
->last_committed_common_params_has_user_gesture());
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
DISABLED_HistoryBackTwiceFromRendererWithoutUserGesture) {
GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url2(embedded_test_server()->GetURL("b.com", "/title2.html"));
GURL url3(embedded_test_server()->GetURL("c.com", "/title3.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
EXPECT_TRUE(NavigateToURL(shell(), url2));
EXPECT_TRUE(NavigateToURL(shell(), url3));
EXPECT_TRUE(ExecJs(shell(), "history.back(); history.back();",
EXECUTE_SCRIPT_NO_USER_GESTURE));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(url2, shell()->web_contents()->GetLastCommittedURL());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
HistoryBackTwiceFromRendererWithUserGesture) {
GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url2(embedded_test_server()->GetURL("b.com", "/title2.html"));
GURL url3(embedded_test_server()->GetURL("c.com", "/title3.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
EXPECT_TRUE(NavigateToURL(shell(), url2));
EXPECT_TRUE(NavigateToURL(shell(), url3));
EXPECT_TRUE(ExecJs(shell(), "history.back(); history.back();"));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(url1, shell()->web_contents()->GetLastCommittedURL());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
BrowserInitiatedLoadPostCommitErrorPage) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url));
RenderFrameHost* root = shell()->web_contents()->GetPrimaryMainFrame();
scoped_refptr<SiteInstance> success_site_instance = root->GetSiteInstance();
std::string error_html = "Error page";
TestNavigationObserver error_observer(shell()->web_contents());
controller.LoadPostCommitErrorPage(root, url, error_html,
net::ERR_BLOCKED_BY_CLIENT);
error_observer.Wait();
scoped_refptr<SiteInstance> error_site_instance =
shell()->web_contents()->GetPrimaryMainFrame()->GetSiteInstance();
EXPECT_FALSE(error_observer.last_navigation_succeeded());
EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, error_observer.last_net_error_code());
EXPECT_EQ(PAGE_TYPE_ERROR, controller.GetLastCommittedEntry()->GetPageType());
EXPECT_EQ(error_html, EvalJs(shell(), "document.body.innerHTML"));
if (!SiteIsolationPolicy::IsErrorPageIsolationEnabled(true))
return;
EXPECT_NE(success_site_instance, error_site_instance);
EXPECT_TRUE(
success_site_instance->IsRelatedSiteInstance(error_site_instance.get()));
EXPECT_NE(success_site_instance->GetProcess()->GetID(),
error_site_instance->GetProcess()->GetID());
EXPECT_EQ(GURL(kUnreachableWebDataURL), error_site_instance->GetSiteURL());
EXPECT_TRUE(
error_site_instance->GetProcess()->GetProcessLock().is_error_page());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
BrowserInitiatedLoadPostCommitErrorPageForSubframe) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe.html"));
EXPECT_TRUE(NavigateToURL(shell(), url));
RenderFrameHost* child =
ChildFrameAt(shell()->web_contents()->GetPrimaryMainFrame(), 0);
scoped_refptr<SiteInstance> success_site_instance = child->GetSiteInstance();
std::string error_html = "Error page";
TestNavigationObserver error_observer(shell()->web_contents());
controller.LoadPostCommitErrorPage(child, url, error_html,
net::ERR_BLOCKED_BY_CLIENT);
error_observer.Wait();
child = ChildFrameAt(shell()->web_contents()->GetPrimaryMainFrame(), 0);
EXPECT_FALSE(error_observer.last_navigation_succeeded());
EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, error_observer.last_net_error_code());
EXPECT_EQ(child->GetLastCommittedURL(), url);
EXPECT_EQ(error_html, EvalJs(child, "document.body.innerHTML"));
EXPECT_TRUE(IsExpectedSubframeErrorTransition(success_site_instance.get(),
child->GetSiteInstance()));
}
#if BUILDFLAG(IS_CHROMEOS)
#define MAYBE_BrowserInitiatedLoadPostCommitErrorPageIgnoredForFramePendingDeletion \
DISABLED_BrowserInitiatedLoadPostCommitErrorPageIgnoredForFramePendingDeletion
#else
#define MAYBE_BrowserInitiatedLoadPostCommitErrorPageIgnoredForFramePendingDeletion \
BrowserInitiatedLoadPostCommitErrorPageIgnoredForFramePendingDeletion
#endif
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
MAYBE_BrowserInitiatedLoadPostCommitErrorPageIgnoredForFramePendingDeletion) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url(embedded_test_server()->GetURL("a.com", "/page_with_iframe.html"));
EXPECT_TRUE(NavigateToURL(shell(), url));
RenderFrameHost* frame = shell()->web_contents()->GetPrimaryMainFrame();
EXPECT_TRUE(ExecJs(frame, R"(
window.onunload=function(e){
window.domAutomationController.send('done');
};)"));
DisableBackForwardCacheForTesting(contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
DOMMessageQueue dom_message_queue(frame);
GURL cross_process_url(
embedded_test_server()->GetURL("b.com", "/page_with_iframe.html"));
shell()->LoadURL(cross_process_url);
std::string message;
EXPECT_TRUE(dom_message_queue.WaitForMessage(&message));
EXPECT_EQ("\"done\"", message);
EXPECT_TRUE(static_cast<RenderFrameHostImpl*>(frame)->IsPendingDeletion());
std::string error_html = "Error page";
DidStartNavigationObserver did_start_navigation_observer(
shell()->web_contents());
controller.LoadPostCommitErrorPage(frame, url, error_html,
net::ERR_BLOCKED_BY_CLIENT);
EXPECT_FALSE(did_start_navigation_observer.observed());
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
BrowserInitiatedLoadPostCommitErrorPageWithAboutBlankUrl) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe.html"));
EXPECT_TRUE(NavigateToURL(shell(), url));
RenderFrameHost* child =
ChildFrameAt(shell()->web_contents()->GetPrimaryMainFrame(), 0);
scoped_refptr<SiteInstance> success_site_instance = child->GetSiteInstance();
std::string error_html = "Error page";
GURL error_url("about:blank#error");
TestNavigationObserver error_observer(shell()->web_contents());
controller.LoadPostCommitErrorPage(child, error_url, error_html,
net::ERR_BLOCKED_BY_CLIENT);
error_observer.Wait();
child = ChildFrameAt(shell()->web_contents()->GetPrimaryMainFrame(), 0);
EXPECT_FALSE(error_observer.last_navigation_succeeded());
EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, error_observer.last_net_error_code());
EXPECT_EQ(child->GetLastCommittedURL(), error_url);
EXPECT_EQ(error_html, EvalJs(child, "document.body.innerHTML"));
EXPECT_TRUE(IsExpectedSubframeErrorTransition(success_site_instance.get(),
child->GetSiteInstance()));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
LoadPostCommitErrorPageFromPopupWithoutCommittedEntry) {
GURL url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url));
GURL hung_url(embedded_test_server()->GetURL("/hung"));
Shell* popup;
{
ShellAddedObserver new_shell_observer;
EXPECT_TRUE(ExecJs(shell(), "var window = window.open('/hung');"));
popup = new_shell_observer.GetShell();
}
WebContentsImpl* popup_contents =
static_cast<WebContentsImpl*>(popup->web_contents());
NavigationControllerImpl& controller = popup_contents->GetController();
RenderFrameHostImpl* popup_main_frame = popup_contents->GetPrimaryMainFrame();
scoped_refptr<SiteInstance> original_site_instance =
popup_main_frame->GetSiteInstance();
EXPECT_EQ(GURL(), popup_main_frame->GetLastCommittedURL());
EXPECT_FALSE(popup_main_frame->has_committed_any_navigation());
std::string error_html = "Error page";
TestNavigationObserver error_observer(popup_contents);
controller.LoadPostCommitErrorPage(popup_main_frame,
popup_main_frame->GetLastCommittedURL(),
error_html, net::ERR_BLOCKED_BY_CLIENT);
error_observer.Wait();
popup_main_frame = popup_contents->GetPrimaryMainFrame();
EXPECT_EQ(popup_main_frame->GetLastCommittedURL(), GURL("about:blank"));
EXPECT_FALSE(error_observer.last_navigation_succeeded());
EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, error_observer.last_net_error_code());
EXPECT_EQ(error_html, EvalJs(popup_main_frame, "document.body.innerHTML"));
scoped_refptr<SiteInstance> error_site_instance =
popup_main_frame->GetSiteInstance();
EXPECT_NE(original_site_instance, error_site_instance);
EXPECT_EQ(GURL(kUnreachableWebDataURL), error_site_instance->GetSiteURL());
EXPECT_EQ(GURL("about:blank"), popup_contents->GetVisibleURL());
EXPECT_EQ(false, EvalJs(shell()->web_contents()->GetPrimaryMainFrame(),
"!!(window.closed)"));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
LoadPostCommitErrorPageFromFrameWithoutCommittedEntry) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url));
GURL hung_url(embedded_test_server()->GetURL("/hung"));
{
TestNavigationManager hung_nav(contents(), hung_url);
EXPECT_TRUE(ExecJs(shell(), R"(
var iframe = document.createElement('iframe');
iframe.src = '/hung';
document.body.appendChild(iframe);
)"));
EXPECT_TRUE(hung_nav.WaitForRequestStart());
}
RenderFrameHostImpl* child = static_cast<RenderFrameHostImpl*>(
ChildFrameAt(shell()->web_contents()->GetPrimaryMainFrame(), 0));
scoped_refptr<SiteInstance> success_site_instance = child->GetSiteInstance();
EXPECT_EQ(GURL(), child->GetLastCommittedURL());
EXPECT_FALSE(child->has_committed_any_navigation());
EXPECT_EQ(true, EvalJs(shell()->web_contents()->GetPrimaryMainFrame(),
"!!(iframe.contentDocument)"));
std::string error_html = "Error page";
TestNavigationObserver error_observer(shell()->web_contents());
controller.LoadPostCommitErrorPage(child, child->GetLastCommittedURL(),
error_html, net::ERR_BLOCKED_BY_CLIENT);
error_observer.Wait();
child = static_cast<RenderFrameHostImpl*>(
ChildFrameAt(shell()->web_contents()->GetPrimaryMainFrame(), 0));
EXPECT_EQ(child->GetLastCommittedURL(), GURL("about:blank"));
EXPECT_FALSE(error_observer.last_navigation_succeeded());
EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, error_observer.last_net_error_code());
EXPECT_EQ(error_html, EvalJs(child, "document.body.innerHTML"));
EXPECT_TRUE(IsExpectedSubframeErrorTransition(success_site_instance.get(),
child->GetSiteInstance()));
EXPECT_EQ(false, EvalJs(shell()->web_contents()->GetPrimaryMainFrame(),
"!!(iframe.contentDocument)"));
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
LoadPostCommitErrorPageFromFrameWithoutCommittedEntryBlockedByCSP) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url));
EXPECT_TRUE(ExecJs(shell(),
R"(var meta = document.createElement('meta');
meta.httpEquiv = 'Content-Security-Policy';
meta.content = "frame-src 'self'";
document.getElementsByTagName('head')[0].appendChild(meta);)"));
GURL hung_url(embedded_test_server()->GetURL("/hung"));
{
TestNavigationManager hung_nav(contents(), hung_url);
EXPECT_TRUE(ExecJs(shell(), R"(
var iframe = document.createElement('iframe');
iframe.src = '/hung';
document.body.appendChild(iframe);
)"));
EXPECT_TRUE(hung_nav.WaitForRequestStart());
}
RenderFrameHostImpl* child = static_cast<RenderFrameHostImpl*>(
ChildFrameAt(shell()->web_contents()->GetPrimaryMainFrame(), 0));
scoped_refptr<SiteInstance> success_site_instance = child->GetSiteInstance();
EXPECT_EQ(GURL(), child->GetLastCommittedURL());
EXPECT_FALSE(child->has_committed_any_navigation());
EXPECT_EQ(true, EvalJs(shell()->web_contents()->GetPrimaryMainFrame(),
"!!(iframe.contentDocument)"));
std::string error_html = "Error page";
TestNavigationObserver error_observer(shell()->web_contents());
controller.LoadPostCommitErrorPage(child, child->GetLastCommittedURL(),
error_html, net::ERR_BLOCKED_BY_CLIENT);
error_observer.Wait();
EXPECT_EQ(child->GetLastCommittedURL(), GURL("about:blank"));
EXPECT_FALSE(error_observer.last_navigation_succeeded());
EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, error_observer.last_net_error_code());
EXPECT_EQ(error_html, EvalJs(child, "document.body.innerHTML"));
EXPECT_TRUE(IsExpectedSubframeErrorTransition(success_site_instance.get(),
child->GetSiteInstance()));
EXPECT_EQ(false, EvalJs(shell()->web_contents()->GetPrimaryMainFrame(),
"!!(iframe.contentDocument)"));
}
class NavigationStarterBeforeDidCommitNavigation
: public DidCommitNavigationInterceptor {
public:
NavigationStarterBeforeDidCommitNavigation(WebContentsImpl* web_contents,
Shell* shell,
const GURL& url_to_intercept,
const GURL& url_to_start)
: DidCommitNavigationInterceptor(web_contents),
shell_(shell),
url_to_intercept_(url_to_intercept),
url_to_start_(url_to_start) {}
~NavigationStarterBeforeDidCommitNavigation() override = default;
private:
bool WillProcessDidCommitNavigation(
RenderFrameHost* render_frame_host,
NavigationRequest* navigation_request,
mojom::DidCommitProvisionalLoadParamsPtr* params,
mojom::DidCommitProvisionalLoadInterfaceParamsPtr* interface_params)
override {
if ((**params).url == *url_to_intercept_) {
shell_->LoadURL(*url_to_start_);
}
return true;
}
raw_ptr<Shell> shell_;
const raw_ref<const GURL> url_to_intercept_;
const raw_ref<const GURL> url_to_start_;
};
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
MultipleSameDocumentNavigations) {
GURL url1(embedded_test_server()->GetURL("/title1.html"));
GURL url2(embedded_test_server()->GetURL("/title1.html#foo"));
GURL url3(embedded_test_server()->GetURL("/title1.html#bar"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
NavigationStarterBeforeDidCommitNavigation url3_navigation_starter(
contents(), shell(), url2, url3);
TestNavigationObserver navigations_observer(shell()->web_contents(), 2);
FrameNavigateParamsCapturer url2_capturer(
contents()->GetPrimaryFrameTree().root());
shell()->LoadURL(url2);
url2_capturer.Wait();
EXPECT_FALSE(url2_capturer.is_renderer_initiated());
EXPECT_TRUE(url2_capturer.is_same_document());
navigations_observer.Wait();
EXPECT_EQ(url3, contents()->GetLastCommittedURL());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
BackOnBrowserInitiatedErrorPageNavigation) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url1(embedded_test_server()->GetURL("/title1.html"));
GURL url2(embedded_test_server()->GetURL("/title2.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
int initial_entry_index = controller.GetLastCommittedEntryIndex();
EXPECT_TRUE(NavigateToURL(shell(), url2));
TestNavigationObserver error_observer(shell()->web_contents());
controller.LoadPostCommitErrorPage(
shell()->web_contents()->GetPrimaryMainFrame(), url2, "Error Page",
net::ERR_BLOCKED_BY_CLIENT);
error_observer.Wait();
EXPECT_EQ(PAGE_TYPE_ERROR, controller.GetLastCommittedEntry()->GetPageType());
EXPECT_EQ(2, controller.GetEntryCount());
controller.GoBack();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(initial_entry_index, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(PAGE_TYPE_NORMAL, controller.GetEntryAtOffset(1)->GetPageType());
EXPECT_EQ(url2, controller.GetEntryAtOffset(1)->GetURL());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
ReloadOnBrowserInitiatedErrorPageNavigation) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url));
int initial_entry_index = controller.GetLastCommittedEntryIndex();
int initial_entry_id = controller.GetLastCommittedEntry()->GetUniqueID();
TestNavigationObserver error_observer(shell()->web_contents());
controller.LoadPostCommitErrorPage(
shell()->web_contents()->GetPrimaryMainFrame(), url, "Error Page",
net::ERR_BLOCKED_BY_CLIENT);
error_observer.Wait();
EXPECT_EQ(PAGE_TYPE_ERROR, controller.GetLastCommittedEntry()->GetPageType());
EXPECT_EQ(1, controller.GetEntryCount());
controller.Reload(ReloadType::NORMAL, false);
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(initial_entry_index, controller.GetLastCommittedEntryIndex());
EXPECT_EQ(initial_entry_id,
controller.GetLastCommittedEntry()->GetUniqueID());
EXPECT_EQ(PAGE_TYPE_NORMAL,
controller.GetLastCommittedEntry()->GetPageType());
EXPECT_FALSE(controller.CanGoForward());
EXPECT_EQ(1, controller.GetEntryCount());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
CloneOnBrowserInitiatedErrorPageNavigation) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL url(embedded_test_server()->GetURL("/title2.html"));
EXPECT_TRUE(NavigateToURL(shell(), url));
int initial_entry_id = controller.GetLastCommittedEntry()->GetUniqueID();
std::u16string initial_title = controller.GetLastCommittedEntry()->GetTitle();
TestNavigationObserver error_observer(shell()->web_contents());
controller.LoadPostCommitErrorPage(
shell()->web_contents()->GetPrimaryMainFrame(), url, "Error Page",
net::ERR_BLOCKED_BY_CLIENT);
error_observer.Wait();
EXPECT_EQ(PAGE_TYPE_ERROR, controller.GetLastCommittedEntry()->GetPageType());
EXPECT_EQ(1, controller.GetEntryCount());
std::unique_ptr<WebContents> new_tab = shell()->web_contents()->Clone();
WebContentsImpl* new_tab_impl = static_cast<WebContentsImpl*>(new_tab.get());
NavigationController& new_controller = new_tab_impl->GetController();
EXPECT_TRUE(new_controller.IsInitialNavigation());
EXPECT_TRUE(new_controller.NeedsReload());
EXPECT_EQ(PAGE_TYPE_ERROR,
new_controller.GetLastCommittedEntry()->GetPageType());
{
TestNavigationObserver clone_observer(new_tab.get());
new_controller.LoadIfNecessary();
clone_observer.Wait();
}
EXPECT_NE(initial_entry_id,
new_controller.GetLastCommittedEntry()->GetUniqueID());
EXPECT_EQ(url, new_controller.GetLastCommittedEntry()->GetURL());
EXPECT_EQ(initial_title, new_controller.GetLastCommittedEntry()->GetTitle());
EXPECT_EQ(PAGE_TYPE_NORMAL,
new_controller.GetLastCommittedEntry()->GetPageType());
EXPECT_EQ(1, new_controller.GetEntryCount());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTestNoServer,
ClientRedirectAfterSameDocumentNavigation) {
net::test_server::ControllableHttpResponse response(embedded_test_server(),
"/foo.html");
ASSERT_TRUE(embedded_test_server()->Start());
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
const GURL start_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
EXPECT_EQ(start_url, controller.GetLastCommittedEntry()->GetURL());
const GURL main_url(embedded_test_server()->GetURL("/foo.html"));
const GURL last_url(embedded_test_server()->GetURL("/title3.html"));
TestNavigationManager observer(shell()->web_contents(), last_url);
shell()->LoadURL(main_url);
response.WaitForRequest();
response.Send(
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"\r\n"
"<html><script>"
"window.location.replace('#a');"
"window.location='/title3.html';"
"</script></html>");
ASSERT_TRUE(observer.WaitForNavigationFinished());
EXPECT_EQ(last_url, controller.GetLastCommittedEntry()->GetURL());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_TRUE(controller.CanGoBack());
TestNavigationObserver back_load_observer(shell()->web_contents());
controller.GoBack();
back_load_observer.Wait();
EXPECT_EQ(start_url, controller.GetLastCommittedEntry()->GetURL());
}
class SandboxedNavigationControllerBrowserTest
: public NavigationControllerBrowserTest {
protected:
void SetupNavigation() {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL preload_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_links.html"));
EXPECT_TRUE(NavigateToURL(shell(), preload_url));
ASSERT_EQ(1, controller.GetEntryCount());
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_sandbox_iframe.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
ASSERT_EQ(2, controller.GetEntryCount());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(2U, root->child_count());
ASSERT_NE(nullptr, root->child_at(0));
ASSERT_NE(nullptr, root->child_at(1));
ASSERT_NE(nullptr, root->child_at(1)->child_at(0));
GURL sub_subframe_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_2.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), sub_subframe_url));
ASSERT_EQ(3, controller.GetEntryCount());
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(1)->child_at(0),
sub_subframe_url));
ASSERT_EQ(4, controller.GetEntryCount());
std::string script = "document.getElementById('test_anchor').click()";
EXPECT_TRUE(ExecJs(root->child_at(1), script));
ASSERT_EQ(5, controller.GetEntryCount());
EXPECT_EQ(4, controller.GetCurrentEntryIndex());
}
private:
base::test::ScopedFeatureList feature_list_;
};
IN_PROC_BROWSER_TEST_P(SandboxedNavigationControllerBrowserTest,
TopLevelNavigationFromSandboxSource) {
SetupNavigation();
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
std::string back_script = "history.back();";
std::string forward_script = "history.forward();";
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
EXPECT_TRUE(ExecJs(root->child_at(1), back_script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(3, controller.GetCurrentEntryIndex());
EXPECT_TRUE(ExecJs(root->child_at(1), back_script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetCurrentEntryIndex());
EXPECT_TRUE(ExecJs(root->child_at(1), back_script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetCurrentEntryIndex());
EXPECT_TRUE(ExecJs(root->child_at(1), back_script));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetCurrentEntryIndex());
ASSERT_TRUE(controller.CanGoBack());
controller.GoBack();
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
controller.GoForward();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(2, controller.GetCurrentEntryIndex());
root->child_at(1)
->current_frame_host()
->GetRenderWidgetHost()
->ForwardMouseEvent(blink::WebMouseEvent(
blink::WebInputEvent::Type::kMouseUp, gfx::PointF(), gfx::PointF(),
blink::WebPointerProperties::Button::kBack, 0, 0,
base::TimeTicks::Now()));
RunUntilInputProcessed(
root->child_at(1)->current_frame_host()->GetRenderWidgetHost());
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
}
class SandboxedNavigationControllerWithBfcacheBrowserTest
: public NavigationControllerBrowserTest {
protected:
void SetUp() override {
feature_list_.InitWithFeaturesAndParameters(
GetDefaultEnabledBackForwardCacheFeaturesForTesting(
false),
GetDefaultDisabledBackForwardCacheFeaturesForTesting());
NavigationControllerBrowserTest::SetUp();
}
private:
base::test::ScopedFeatureList feature_list_;
};
IN_PROC_BROWSER_TEST_P(SandboxedNavigationControllerWithBfcacheBrowserTest,
BackNavigationToCachedPageNotAllowed) {
GURL cached_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL main_url(embedded_test_server()->GetURL(
"b.com", "/navigation_controller/page_with_sandbox_iframe.html"));
EXPECT_TRUE(NavigateToURL(shell(), cached_url));
RenderFrameHostImpl* cached_rfh = static_cast<RenderFrameHostImpl*>(
shell()->web_contents()->GetPrimaryMainFrame());
content::RenderFrameDeletedObserver observer(cached_rfh);
EXPECT_TRUE(NavigateToURL(shell(), main_url));
ASSERT_FALSE(observer.deleted());
EXPECT_TRUE(cached_rfh->IsInBackForwardCache());
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(2UL, root->child_count());
FrameTreeNode* sanboxed_iframe = root->child_at(1);
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
EXPECT_TRUE(ExecJs(sanboxed_iframe, "history.back();"));
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
}
class SandboxedNavigationControllerPopupBrowserTest
: public NavigationControllerBrowserTest {
protected:
void SetupNavigation() {
EXPECT_EQ(1u, Shell::windows().size());
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
GURL preload_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_sandboxed_iframe_popup.html"));
EXPECT_TRUE(NavigateToURL(shell(), preload_url));
ASSERT_EQ(1, controller.GetEntryCount());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(1U, root->child_count());
ASSERT_NE(nullptr, root->child_at(0));
ShellAddedObserver new_shell_observer;
std::string script = "document.getElementById('test_link').click()";
EXPECT_TRUE(ExecJs(root->child_at(0), script));
popup_shell_ = new_shell_observer.GetShell();
EXPECT_TRUE(WaitForLoadStop(popup_shell_->web_contents()));
FrameTreeNode* popup_root =
static_cast<WebContentsImpl*>(popup_shell_->web_contents())
->GetPrimaryFrameTree()
.root();
std::string popup_script = "document.getElementById('test_anchor').click()";
EXPECT_TRUE(ExecJs(popup_root, popup_script));
}
protected:
raw_ptr<Shell, DanglingUntriaged> popup_shell_ = nullptr;
private:
base::test::ScopedFeatureList feature_list_;
};
IN_PROC_BROWSER_TEST_P(SandboxedNavigationControllerPopupBrowserTest,
NavigateSelf) {
SetupNavigation();
std::string back_script = "history.back();";
FrameTreeNode* root =
static_cast<WebContentsImpl*>(popup_shell_->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
popup_shell_->web_contents()->GetController());
ASSERT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
EXPECT_TRUE(ExecJs(root, back_script));
EXPECT_TRUE(WaitForLoadStop(popup_shell_->web_contents()));
EXPECT_EQ(0, controller.GetCurrentEntryIndex());
}
class NavigationControllerMainDocumentSequenceNumberBrowserTest
: public NavigationControllerBrowserTest,
public WebContentsObserver {
protected:
void SetUpOnMainThread() override {
NavigationControllerBrowserTest::SetUpOnMainThread();
WebContentsObserver::Observe(shell()->web_contents());
}
void DidFinishNavigation(NavigationHandle* navigation_handle) override {
main_frame_document_sequence_numbers_.push_back(
shell()
->web_contents()
->GetController()
.GetLastCommittedEntry()
->GetMainFrameDocumentSequenceNumber());
}
std::vector<int64_t> GetProcessedMainDocumentSequenceNumbers() {
std::vector<int64_t> ids = main_frame_document_sequence_numbers_;
std::sort(ids.begin(), ids.end());
std::map<int64_t, int64_t> compressor;
int current_id = 0;
for (int64_t value : ids) {
if (compressor.find(value) == compressor.end())
compressor[value] = ++current_id;
}
std::vector<int64_t> result;
for (int64_t value : main_frame_document_sequence_numbers_)
result.push_back(compressor[value]);
return result;
}
private:
std::vector<int64_t> main_frame_document_sequence_numbers_;
};
IN_PROC_BROWSER_TEST_P(
NavigationControllerMainDocumentSequenceNumberBrowserTest,
SubframeNavigation) {
const GURL url1(
embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
const GURL url2(embedded_test_server()->GetURL("/title1.html"));
const GURL url3(embedded_test_server()->GetURL("/title2.html"));
const char kChildFrameId[] = "child0";
EXPECT_TRUE(NavigateToURL(shell(), url1));
EXPECT_TRUE(
NavigateIframeToURL(shell()->web_contents(), kChildFrameId, url2));
EXPECT_TRUE(NavigateToURL(shell(), url3));
{
TestNavigationObserver navigation_observer(
shell()->web_contents(), IsBackForwardCacheEnabled() ? 1 : 2);
shell()->GoBackOrForward(-1);
navigation_observer.WaitForNavigationFinished();
}
if (!IsBackForwardCacheEnabled()) {
EXPECT_THAT(GetProcessedMainDocumentSequenceNumbers(),
ElementsAre(1, 1, 1, 2, 1, 1));
} else {
EXPECT_THAT(GetProcessedMainDocumentSequenceNumbers(),
ElementsAre(1, 1, 1, 2, 1));
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerMainDocumentSequenceNumberBrowserTest,
SameDocument) {
const GURL url1(embedded_test_server()->GetURL("/title1.html"));
const GURL url1_fragment(embedded_test_server()->GetURL("/title1.html#id_1"));
const GURL url2(embedded_test_server()->GetURL("/title2.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
EXPECT_TRUE(NavigateToURL(shell(), url1_fragment));
EXPECT_TRUE(NavigateToURL(shell(), url2));
{
TestNavigationObserver navigation_observer(shell()->web_contents());
shell()->GoBackOrForward(-1);
navigation_observer.WaitForNavigationFinished();
}
EXPECT_THAT(GetProcessedMainDocumentSequenceNumbers(),
ElementsAre(1, 1, 2, 1));
}
namespace {
class DidCommitNavigationCanceller : public DidCommitNavigationInterceptor {
using CallbackScriptRunner = base::OnceCallback<void()>;
public:
DidCommitNavigationCanceller(WebContents* web_contents,
const GURL& url_to_cancel,
CallbackScriptRunner callback)
: DidCommitNavigationInterceptor(web_contents),
url_to_cancel_(url_to_cancel) {
callback_ = std::move(callback);
}
bool WillProcessDidCommitNavigation(
RenderFrameHost* render_frame_host,
NavigationRequest* navigation_request,
mojom::DidCommitProvisionalLoadParamsPtr* params,
mojom::DidCommitProvisionalLoadInterfaceParamsPtr* interface_params)
override {
if (navigation_request->GetURL() == url_to_cancel_) {
std::move(callback_).Run();
return false;
}
return true;
}
private:
CallbackScriptRunner callback_;
GURL url_to_cancel_;
};
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
CrossProcessIframeToInvalidURLCancelsRedirectSpoof) {
if (!AreAllSitesIsolatedForTesting())
return;
if (ShouldQueueNavigationsWhenPendingCommitRFHExists()) {
return;
}
const GURL main_frame_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
const GURL main_frame_url_2(embedded_test_server()->GetURL("/title2.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_frame_url));
FrameTreeNode* iframe = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root()
->child_at(0);
DidCommitNavigationCanceller canceller(
shell()->web_contents(), main_frame_url_2,
base::BindLambdaForTesting([iframe]() {
EXPECT_TRUE(ExecJs(
iframe, "parent.location.href = 'chrome-untrusted://1234';"));
}));
EXPECT_FALSE(NavigateToURL(shell(), main_frame_url_2));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
EXPECT_EQ(controller.GetVisibleEntry()->GetVirtualURL(),
shell()->web_contents()->GetLastCommittedURL());
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
NavigationAbortDuringLongCrossProcessIframeBeforeUnload) {
if (!AreAllSitesIsolatedForTesting())
return;
const GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
const GURL navigated_url(
embedded_test_server()->GetURL("a.com", "/title1.html"));
WebContentsImpl* web_contents =
static_cast<WebContentsImpl*>(shell()->web_contents());
FrameTreeNode* root = web_contents->GetPrimaryFrameTree().root();
EXPECT_TRUE(NavigateToURL(shell(), main_url));
std::string script =
"window.addEventListener('beforeunload', function (event) {"
" event.returnValue='blocked'"
"});";
EXPECT_TRUE(ExecJs(root->child_at(0), script));
NavigationHandleObserver abort_observer(web_contents, navigated_url);
BeforeUnloadBlockingDelegate beforeunload_pauser(web_contents);
EXPECT_TRUE(ExecJs(shell(), "location.href = 'title1.html'"));
beforeunload_pauser.Wait();
EXPECT_TRUE(ExecJs(shell(), "document.write()"));
EXPECT_EQ(42, EvalJs(shell(), "12 + 30").ExtractInt());
EXPECT_FALSE(abort_observer.has_committed());
}
namespace {
std::unique_ptr<net::test_server::HttpResponse> HandleMethodOnly(
net::test_server::HttpMethod method,
const net::test_server::HttpRequest& request) {
if (request.relative_url != "/handle-method-only")
return nullptr;
if (request.method != method) {
return std::make_unique<net::test_server::RawHttpResponse>("", "");
}
std::unique_ptr<net::test_server::BasicHttpResponse> response =
std::make_unique<net::test_server::BasicHttpResponse>();
response->set_content_type("text/html");
response->set_content("Success!");
return response;
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTestNoServer,
UpdateMethodOn301RedirectError) {
embedded_test_server()->RegisterRequestHandler(
base::BindRepeating(&HandleMethodOnly, net::test_server::METHOD_POST));
ASSERT_TRUE(embedded_test_server()->Start());
GURL start_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
GURL post_only_url = embedded_test_server()->GetURL("/handle-method-only");
GURL form_action_url(embedded_test_server()->GetURL("/server-redirect-301?" +
post_only_url.spec()));
TestNavigationObserver form_nav_observer(shell()->web_contents(), 1);
EXPECT_TRUE(ExecJs(shell()->web_contents(),
JsReplace("var form = document.createElement('form');"
"form.method = 'POST';"
"form.action = $1;"
"document.body.appendChild(form);"
"form.submit();",
form_action_url.spec())));
form_nav_observer.Wait();
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(post_only_url, entry->GetURL());
EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
EXPECT_FALSE(entry->GetHasPostData());
TestNavigationObserver reload_observer(shell()->web_contents(), 1);
controller.Reload(ReloadType::NORMAL, false);
reload_observer.Wait();
entry = controller.GetLastCommittedEntry();
EXPECT_EQ(post_only_url, entry->GetURL());
EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTestNoServer,
UpdateMethodOn307RedirectError) {
embedded_test_server()->RegisterRequestHandler(
base::BindRepeating(&HandleMethodOnly, net::test_server::METHOD_GET));
ASSERT_TRUE(embedded_test_server()->Start());
GURL start_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
GURL get_only_url = embedded_test_server()->GetURL("/handle-method-only");
GURL form_action_url(embedded_test_server()->GetURL("/server-redirect-307?" +
get_only_url.spec()));
TestNavigationObserver form_nav_observer(shell()->web_contents(), 1);
EXPECT_TRUE(ExecJs(shell()->web_contents(),
JsReplace("var form = document.createElement('form');"
"form.method = 'POST';"
"form.action = $1;"
"document.body.appendChild(form);"
"form.submit();",
form_action_url.spec())));
form_nav_observer.Wait();
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(get_only_url, entry->GetURL());
EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
EXPECT_TRUE(entry->GetHasPostData());
TestNavigationObserver reload_observer(shell()->web_contents(), 1);
controller.Reload(ReloadType::NORMAL, false);
reload_observer.Wait();
entry = controller.GetLastCommittedEntry();
EXPECT_EQ(get_only_url, entry->GetURL());
EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
SameDocumentNavigationToHttpPortZero) {
auto interceptor = URLLoaderInterceptor::ServeFilesFromDirectoryAtOrigin(
"content/test/data", GURL("http://another-site.com:0"));
GURL page_url(embedded_test_server()->GetURL(
"foo.com", "/navigation_controller/simple_page_1.html"));
EXPECT_TRUE(NavigateToURL(shell(), page_url));
const char kSubframeScriptTemplate[] = R"(
var iframe = document.createElement('iframe');
iframe.src = $1;
document.body.appendChild(iframe);
)";
GURL subframe_initial_url =
embedded_test_server()->GetURL("another-site.com", "/title2.html");
{
TestNavigationObserver subframe_injection_observer(shell()->web_contents(),
1);
ASSERT_TRUE(ExecJs(
shell(), JsReplace(kSubframeScriptTemplate, subframe_initial_url)));
subframe_injection_observer.Wait();
ASSERT_TRUE(subframe_injection_observer.last_navigation_succeeded());
}
GURL::Replacements replace_port_and_ref;
replace_port_and_ref.SetPortStr("0");
replace_port_and_ref.SetRefStr("someRef");
GURL subframe_ref_url =
subframe_initial_url.ReplaceComponents(replace_port_and_ref);
FrameTreeNode* subframe_tree_node =
static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root()
->child_at(0);
ASSERT_TRUE(NavigateToURLFromRenderer(subframe_tree_node, subframe_ref_url));
EXPECT_EQ(subframe_tree_node->current_frame_host()->GetLastCommittedURL(),
GURL("http://another-site.com:0/title2.html#someRef"));
EXPECT_EQ(subframe_tree_node->current_frame_host()->GetLastCommittedOrigin(),
url::Origin::Create(GURL("http://another-site.com:0")));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
NoHistoryOnNavigationToSameUrl) {
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
ASSERT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)")));
FrameTreeNode* child = contents()->GetPrimaryFrameTree().root()->child_at(0);
GURL child_url = child->current_url();
NavigationEntryImpl* previous_entry = controller.GetLastCommittedEntry();
scoped_refptr<FrameNavigationEntry> previous_frame_entry =
previous_entry->GetFrameEntry(child);
EXPECT_EQ(1, controller.GetEntryCount());
{
FrameNavigateParamsCapturer capturer(child);
ASSERT_TRUE(NavigateToURLFromRenderer(child, child_url));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(previous_frame_entry,
controller.GetLastCommittedEntry()->GetFrameEntry(child));
EXPECT_TRUE(capturer.did_replace_entry());
}
ASSERT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)")));
EXPECT_EQ(2, controller.GetEntryCount());
child = contents()->GetPrimaryFrameTree().root()->child_at(0);
child_url = child->current_url();
{
ReplaceState(child, "foo");
EXPECT_EQ("foo", EvalJs(child, "history.state"));
previous_entry = controller.GetLastCommittedEntry();
previous_frame_entry = previous_entry->GetFrameEntry(child);
FrameNavigateParamsCapturer capturer(child);
ASSERT_TRUE(NavigateToURLFromRenderer(child, child_url));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(previous_frame_entry,
controller.GetLastCommittedEntry()->GetFrameEntry(child));
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_EQ("foo", EvalJs(child, "history.state"));
}
{
ReplaceState(child, "foo");
EXPECT_EQ("foo", EvalJs(child, "history.state"));
previous_entry = controller.GetLastCommittedEntry();
previous_frame_entry = previous_entry->GetFrameEntry(child);
FrameNavigateParamsCapturer capturer(child);
ASSERT_TRUE(NavigateFrameToURL(child, child_url));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(previous_frame_entry,
controller.GetLastCommittedEntry()->GetFrameEntry(child));
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_EQ("foo", EvalJs(child, "history.state"));
}
{
ReplaceState(child, "foo");
EXPECT_EQ("foo", EvalJs(child, "history.state"));
previous_entry = controller.GetLastCommittedEntry();
previous_frame_entry = previous_entry->GetFrameEntry(child);
auto url_loader_interceptor = std::make_unique<URLLoaderInterceptor>(
base::BindRepeating([](URLLoaderInterceptor::RequestParams* params) {
network::URLLoaderCompletionStatus status;
status.error_code = net::ERR_NOT_IMPLEMENTED;
params->client->OnComplete(status);
return true;
}));
FrameNavigateParamsCapturer capturer(child);
ASSERT_FALSE(NavigateFrameToURL(child, child_url));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(previous_frame_entry,
controller.GetLastCommittedEntry()->GetFrameEntry(child));
EXPECT_TRUE(capturer.did_replace_entry());
}
{
previous_entry = controller.GetLastCommittedEntry();
previous_frame_entry = previous_entry->GetFrameEntry(child);
TestNavigationObserver observer(shell()->web_contents());
FrameNavigateParamsCapturer capturer(child);
ASSERT_TRUE(NavigateFrameToURL(child, child_url));
capturer.Wait();
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(previous_frame_entry,
controller.GetLastCommittedEntry()->GetFrameEntry(child));
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_EQ("foo", EvalJs(child, "history.state"));
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
NoHistoryOnNavigationToSameURLWithFragment) {
ASSERT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)")));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* child = contents()->GetPrimaryFrameTree().root()->child_at(0);
GURL child_url = child->current_url();
{
TestNavigationObserver observer(shell()->web_contents());
FrameNavigateParamsCapturer capturer(child);
EXPECT_TRUE(ExecJs(child, "location.href = '#bar';"));
capturer.Wait();
observer.Wait();
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_TRUE(capturer.is_same_document());
child_url = child->current_url();
}
ReplaceState(child, "foo");
EXPECT_EQ("foo", EvalJs(child, "history.state"));
NavigationEntryImpl* previous_entry = controller.GetLastCommittedEntry();
scoped_refptr<FrameNavigationEntry> previous_frame_entry =
previous_entry->GetFrameEntry(child);
EXPECT_EQ(2, controller.GetEntryCount());
{
FrameNavigateParamsCapturer capturer(child);
EXPECT_TRUE(NavigateFrameToURL(child, child_url));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
EXPECT_FALSE(capturer.is_same_document());
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(previous_frame_entry,
controller.GetLastCommittedEntry()->GetFrameEntry(child));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ("foo", EvalJs(child, "history.state"));
}
{
ReplaceState(child, "foo");
EXPECT_EQ("foo", EvalJs(child, "history.state"));
previous_entry = controller.GetLastCommittedEntry();
previous_frame_entry = previous_entry->GetFrameEntry(child);
FrameNavigateParamsCapturer capturer(child);
EXPECT_TRUE(NavigateToURLFromRenderer(child, child_url));
capturer.Wait();
EXPECT_TRUE(capturer.is_same_document());
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(previous_frame_entry,
controller.GetLastCommittedEntry()->GetFrameEntry(child));
EXPECT_EQ("foo", EvalJs(child, "history.state"));
EXPECT_EQ(2, controller.GetEntryCount());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
NoHistoryOnSubframeReload) {
ASSERT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)")));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
FrameTreeNode* child = root->child_at(0);
ReplaceState(child, "foo");
EXPECT_EQ("foo", EvalJs(child, "history.state"));
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* previous_entry = controller.GetLastCommittedEntry();
scoped_refptr<FrameNavigationEntry> previous_frame_entry =
previous_entry->GetFrameEntry(child);
{
FrameNavigateParamsCapturer capturer(child);
child->current_frame_host()->Reload();
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(previous_frame_entry,
controller.GetLastCommittedEntry()->GetFrameEntry(child));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ("foo", EvalJs(child, "history.state"));
}
{
ReplaceState(child, "foo");
EXPECT_EQ("foo", EvalJs(child, "history.state"));
previous_entry = controller.GetLastCommittedEntry();
previous_frame_entry = previous_entry->GetFrameEntry(child);
FrameNavigateParamsCapturer capturer(child);
EXPECT_TRUE(ExecJs(child, "location.reload()"));
capturer.Wait();
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(previous_frame_entry,
controller.GetLastCommittedEntry()->GetFrameEntry(child));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ("foo", EvalJs(child, "history.state"));
}
{
ReplaceState(child, "foo");
EXPECT_EQ("foo", EvalJs(child, "history.state"));
previous_entry = controller.GetLastCommittedEntry();
previous_frame_entry = previous_entry->GetFrameEntry(child);
auto url_loader_interceptor = std::make_unique<URLLoaderInterceptor>(
base::BindRepeating([](URLLoaderInterceptor::RequestParams* params) {
network::URLLoaderCompletionStatus status;
status.error_code = net::ERR_NOT_IMPLEMENTED;
params->client->OnComplete(status);
return true;
}));
TestNavigationObserver reload_observer(shell()->web_contents());
FrameNavigateParamsCapturer capturer(child);
child->current_frame_host()->Reload();
capturer.Wait();
EXPECT_FALSE(reload_observer.last_navigation_succeeded());
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(previous_frame_entry,
controller.GetLastCommittedEntry()->GetFrameEntry(child));
EXPECT_EQ(1, controller.GetEntryCount());
url_loader_interceptor.reset();
}
{
previous_entry = controller.GetLastCommittedEntry();
previous_frame_entry = previous_entry->GetFrameEntry(child);
TestNavigationObserver reload_observer(shell()->web_contents());
FrameNavigateParamsCapturer capturer(child);
child->current_frame_host()->Reload();
capturer.Wait();
EXPECT_TRUE(reload_observer.last_navigation_succeeded());
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_EQ(previous_entry, controller.GetLastCommittedEntry());
EXPECT_EQ(previous_frame_entry,
controller.GetLastCommittedEntry()->GetFrameEntry(child));
EXPECT_EQ(1, controller.GetEntryCount());
if (SiteIsolationPolicy::IsErrorPageIsolationEnabled(false)) {
EXPECT_EQ(nullptr, EvalJs(child, "history.state"));
} else {
EXPECT_EQ("foo", EvalJs(child, "history.state"));
}
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
GoBackSameDocumentInRemovedSubframe) {
GURL main_url = embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b,c)");
ASSERT_TRUE(NavigateToURL(shell(), main_url));
NavigationControllerImpl& controller = contents()->GetController();
ASSERT_EQ(1, controller.GetEntryCount());
FrameTreeNode* ftn_a = contents()->GetPrimaryFrameTree().root();
FrameTreeNode* ftn_b = ftn_a->child_at(0);
FrameTreeNode* ftn_c = ftn_a->child_at(1);
EXPECT_TRUE(ExecJs(ftn_a, "window.state = 'a';"));
GURL ps2_url(embedded_test_server()->GetURL("a.com", "/ps2.html"));
{
FrameNavigateParamsCapturer capturer(ftn_a);
ASSERT_TRUE(ExecJs(ftn_a, "history.pushState({}, 'page 2', 'ps2.html')"));
capturer.Wait();
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(ps2_url, controller.GetLastCommittedEntry()->GetURL());
}
{
FrameNavigateParamsCapturer capturer(ftn_c);
ASSERT_TRUE(ExecJs(ftn_c, "history.pushState({}, 'page 3', 'ps3.html')"));
capturer.Wait();
EXPECT_EQ(3, controller.GetEntryCount());
}
{
FrameNavigateParamsCapturer capturer(ftn_c);
ASSERT_TRUE(ExecJs(ftn_c, "history.pushState({}, 'page 4', 'ps4.html')"));
capturer.Wait();
EXPECT_EQ(4, controller.GetEntryCount());
}
GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
{
TestNavigationObserver navigation_observer(contents());
EXPECT_TRUE(NavigateToURLFromRenderer(ftn_b, url_b));
navigation_observer.WaitForNavigationFinished();
}
EXPECT_EQ(5, controller.GetEntryCount());
EXPECT_EQ(4, controller.GetCurrentEntryIndex());
{
TestNavigationObserver navigation_observer(shell()->web_contents());
shell()->GoBackOrForward(-1);
navigation_observer.Wait();
}
EXPECT_EQ(5, controller.GetEntryCount());
EXPECT_EQ(3, controller.GetCurrentEntryIndex());
EXPECT_EQ(ps2_url, controller.GetLastCommittedEntry()->GetURL());
EXPECT_TRUE(ExecJs(ftn_b, "window.state='b';"));
RenderFrameDeletedObserver deleted_observer(ftn_c->current_frame_host());
EXPECT_TRUE(ExecJs(ftn_a,
"var f = document.querySelectorAll('iframe')[1];"
"f.parentNode.removeChild(f);"));
deleted_observer.WaitUntilDeleted();
EXPECT_TRUE(ExecJs(ftn_a, "window.popstateCalled = false"));
EXPECT_TRUE(ExecJs(
ftn_a, "window.onpopstate = () => { window.popstateCalled = true; }"));
shell()->GoBackOrForward(-1);
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(ps2_url, controller.GetLastCommittedEntry()->GetURL());
EXPECT_EQ("a", EvalJs(ftn_a, "window.state"));
EXPECT_EQ("b", EvalJs(ftn_b, "window.state"));
EXPECT_EQ(false, EvalJs(ftn_a, "window.popstateCalled"));
EXPECT_EQ(5, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetCurrentEntryIndex());
shell()->GoBackOrForward(-1);
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(ps2_url, controller.GetLastCommittedEntry()->GetURL());
EXPECT_EQ("a", EvalJs(ftn_a, "window.state"));
EXPECT_EQ("b", EvalJs(ftn_b, "window.state"));
EXPECT_EQ(false, EvalJs(ftn_a, "window.popstateCalled"));
EXPECT_EQ(5, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
shell()->GoBackOrForward(-1);
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(main_url, controller.GetLastCommittedEntry()->GetURL());
EXPECT_EQ("a", EvalJs(ftn_a, "window.state"));
EXPECT_EQ("b", EvalJs(ftn_b, "window.state"));
EXPECT_EQ(true, EvalJs(ftn_a, "window.popstateCalled"));
EXPECT_EQ(5, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetCurrentEntryIndex());
{
FrameNavigateParamsCapturer capturer(ftn_a);
shell()->GoBackOrForward(1);
capturer.Wait();
}
EXPECT_EQ(5, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
EXPECT_EQ(ps2_url, ftn_a->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ("a", EvalJs(ftn_a, "window.state"));
EXPECT_EQ("b", EvalJs(ftn_b, "window.state"));
{
FrameNavigateParamsCapturer capturer(ftn_b);
shell()->GoBackOrForward(3);
capturer.Wait();
}
EXPECT_EQ(url_b, ftn_b->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(5, controller.GetEntryCount());
EXPECT_EQ(4, controller.GetCurrentEntryIndex());
EXPECT_EQ("a", EvalJs(ftn_a, "window.state"));
EXPECT_EQ(nullptr, EvalJs(ftn_b, "window.state"));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
GoBackCrossDocumentInRemovedSubframe) {
GURL main_url = embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)");
ASSERT_TRUE(NavigateToURL(shell(), main_url));
NavigationControllerImpl& controller = contents()->GetController();
ASSERT_EQ(1, controller.GetEntryCount());
FrameTreeNode* ftn_a = contents()->GetPrimaryFrameTree().root();
FrameTreeNode* ftn_b = ftn_a->child_at(0);
EXPECT_TRUE(ExecJs(ftn_a, "window.state = 'a';"));
GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
{
TestNavigationObserver navigation_observer(contents());
EXPECT_TRUE(NavigateToURLFromRenderer(ftn_b, url_b));
navigation_observer.WaitForNavigationFinished();
}
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
RenderFrameDeletedObserver deleted_observer(
ftn_a->child_at(0)->current_frame_host());
EXPECT_TRUE(ExecJs(ftn_a,
"var f = document.querySelector('iframe');"
"f.parentNode.removeChild(f);"));
deleted_observer.WaitUntilDeleted();
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
shell()->GoBackOrForward(-1);
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(main_url, controller.GetLastCommittedEntry()->GetURL());
EXPECT_EQ("a", EvalJs(ftn_a, "window.state"));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetCurrentEntryIndex());
EXPECT_FALSE(controller.CanGoBack());
EXPECT_TRUE(controller.CanGoForward());
shell()->GoBackOrForward(1);
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(main_url, controller.GetLastCommittedEntry()->GetURL());
EXPECT_EQ("a", EvalJs(ftn_a, "window.state"));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
EXPECT_TRUE(controller.CanGoBack());
EXPECT_FALSE(controller.CanGoForward());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
GoForwardCrossDocumentInRemovedSubframe) {
GURL main_url = embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)");
ASSERT_TRUE(NavigateToURL(shell(), main_url));
NavigationControllerImpl& controller = contents()->GetController();
ASSERT_EQ(1, controller.GetEntryCount());
FrameTreeNode* ftn_a = contents()->GetPrimaryFrameTree().root();
FrameTreeNode* ftn_b = contents()->GetPrimaryFrameTree().root()->child_at(0);
GURL orig_subframe_url(ftn_b->current_frame_host()->GetLastCommittedURL());
EXPECT_TRUE(ExecJs(ftn_a, "window.state = 'a';"));
GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
{
TestNavigationObserver navigation_observer(contents());
EXPECT_TRUE(NavigateToURLFromRenderer(ftn_b, url_b));
navigation_observer.WaitForNavigationFinished();
}
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
GURL url_c(embedded_test_server()->GetURL("c.com", "/title2.html"));
{
TestNavigationObserver navigation_observer(contents());
EXPECT_TRUE(NavigateToURLFromRenderer(ftn_b, url_c));
navigation_observer.WaitForNavigationFinished();
}
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetCurrentEntryIndex());
GURL ps_url(embedded_test_server()->GetURL("a.com", "/ps.html"));
{
FrameNavigateParamsCapturer capturer(ftn_a);
ASSERT_TRUE(
ExecJs(ftn_a, "history.pushState({}, 'push state', 'ps.html')"));
capturer.Wait();
EXPECT_EQ(4, controller.GetEntryCount());
EXPECT_EQ(ps_url, controller.GetLastCommittedEntry()->GetURL());
}
shell()->GoBackOrForward(-1);
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(4, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetCurrentEntryIndex());
EXPECT_EQ(main_url, controller.GetLastCommittedEntry()->GetURL());
shell()->GoBackOrForward(-2);
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(4, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetCurrentEntryIndex());
EXPECT_EQ(orig_subframe_url,
ftn_b->current_frame_host()->GetLastCommittedURL());
RenderFrameDeletedObserver deleted_observer(
ftn_a->child_at(0)->current_frame_host());
EXPECT_TRUE(ExecJs(ftn_a,
"var f = document.querySelector('iframe');"
"f.parentNode.removeChild(f);"));
deleted_observer.WaitUntilDeleted();
EXPECT_EQ(4, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetCurrentEntryIndex());
EXPECT_TRUE(ExecJs(ftn_a, "window.popstateCalled = false"));
EXPECT_TRUE(ExecJs(
ftn_a, "window.onpopstate = () => { window.popstateCalled = true; }"));
shell()->GoBackOrForward(1);
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ("a", EvalJs(ftn_a, "window.state"));
EXPECT_EQ(false, EvalJs(ftn_a, "window.popstateCalled"));
EXPECT_EQ(4, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
shell()->GoBackOrForward(1);
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ("a", EvalJs(ftn_a, "window.state"));
EXPECT_EQ(false, EvalJs(ftn_a, "window.popstateCalled"));
EXPECT_EQ(4, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetCurrentEntryIndex());
shell()->GoBackOrForward(1);
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(true, EvalJs(ftn_a, "window.popstateCalled"));
EXPECT_EQ(4, controller.GetEntryCount());
EXPECT_EQ(3, controller.GetCurrentEntryIndex());
EXPECT_TRUE(controller.CanGoBack());
EXPECT_FALSE(controller.CanGoForward());
EXPECT_EQ(ps_url, controller.GetLastCommittedEntry()->GetURL());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
RestoreRemovedSubframe) {
GURL main_url =
embedded_test_server()->GetURL("a.com", "/page_with_iframe.html");
ASSERT_TRUE(NavigateToURL(shell(), main_url));
NavigationControllerImpl& controller = contents()->GetController();
FrameTreeNode* ftn_a = contents()->GetPrimaryFrameTree().root();
FrameTreeNode* ftn_b = ftn_a->child_at(0);
EXPECT_EQ(embedded_test_server()->GetURL("a.com", "/title1.html"),
ftn_b->current_frame_host()->GetLastCommittedURL());
EXPECT_TRUE(ExecJs(ftn_a, "window.state = 'a';"));
GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html"));
{
TestNavigationObserver navigation_observer(contents());
EXPECT_TRUE(NavigateToURLFromRenderer(ftn_b, url_b));
navigation_observer.WaitForNavigationFinished();
}
GURL url_c(embedded_test_server()->GetURL("c.com", "/title3.html"));
{
TestNavigationObserver navigation_observer(contents());
EXPECT_TRUE(NavigateToURLFromRenderer(ftn_b, url_c));
navigation_observer.WaitForNavigationFinished();
}
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetCurrentEntryIndex());
RenderFrameDeletedObserver deleted_observer(
ftn_a->child_at(0)->current_frame_host());
EXPECT_TRUE(ExecJs(ftn_a,
"var f = document.querySelector('iframe');"
"f.parentNode.removeChild(f);"));
deleted_observer.WaitUntilDeleted();
controller.GoBack();
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ("a", EvalJs(ftn_a, "window.state"));
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
DisableBackForwardCacheForTesting(shell()->web_contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL("a.com", "/title2.html")));
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetCurrentEntryIndex());
controller.GoBack();
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
EXPECT_EQ(url_b,
ftn_a->child_at(0)->current_frame_host()->GetLastCommittedURL());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
ReloadSadFrameWithSubframeHistoryNavigation) {
IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess());
GURL main_url = embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b,c)");
ASSERT_TRUE(NavigateToURL(shell(), main_url));
NavigationControllerImpl& controller = contents()->GetController();
FrameTreeNode* ftn_a = contents()->GetPrimaryFrameTree().root();
FrameTreeNode* ftn_b = ftn_a->child_at(0);
FrameTreeNode* ftn_c = ftn_a->child_at(1);
GURL url_b(ftn_b->current_frame_host()->GetLastCommittedURL());
GURL url_c(ftn_c->current_frame_host()->GetLastCommittedURL());
GURL url_d(embedded_test_server()->GetURL("d.com", "/title2.html"));
{
TestNavigationObserver navigation_observer(contents());
EXPECT_TRUE(NavigateToURLFromRenderer(ftn_b, url_d));
navigation_observer.WaitForNavigationFinished();
}
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
EXPECT_EQ(url_d, ftn_b->current_frame_host()->GetLastCommittedURL());
RenderProcessHost* process_c = ftn_c->current_frame_host()->GetProcess();
RenderProcessHostWatcher crash_observer(
process_c, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
process_c->Shutdown(0);
crash_observer.Wait();
EXPECT_FALSE(ftn_c->current_frame_host()->IsRenderFrameLive());
EXPECT_TRUE(ftn_c->current_frame_host()->GetLastCommittedURL().is_empty());
controller.GoBack();
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetCurrentEntryIndex());
EXPECT_EQ(url_b, ftn_b->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(url_c, ftn_c->current_frame_host()->GetLastCommittedURL());
EXPECT_TRUE(ftn_c->current_frame_host()->IsRenderFrameLive());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
SubframeGoesBackAndSiblingHasNoFrameEntry) {
GURL main_url =
embedded_test_server()->GetURL("a.com", "/page_with_iframe.html");
ASSERT_TRUE(NavigateToURL(shell(), main_url));
NavigationControllerImpl& controller = contents()->GetController();
FrameTreeNode* ftn_a = contents()->GetPrimaryFrameTree().root();
FrameTreeNode* ftn_b = ftn_a->child_at(0);
EXPECT_EQ(embedded_test_server()->GetURL("a.com", "/title1.html"),
ftn_b->current_frame_host()->GetLastCommittedURL());
EXPECT_TRUE(ExecJs(ftn_a,
"var f = document.createElement('iframe');"
"f.src = 'javascript:void(0)';"
"document.body.appendChild(f);"));
FrameTreeNode* ftn_c = ftn_a->child_at(1);
EXPECT_TRUE(ExecJs(ftn_c, "window.state='c';"));
{
FrameNavigateParamsCapturer capturer(ftn_b);
EXPECT_TRUE(ExecJs(ftn_b, "location.hash = 'foo'"));
capturer.Wait();
EXPECT_TRUE(capturer.is_same_document());
}
{
FrameNavigateParamsCapturer capturer(ftn_b);
controller.GoBack();
capturer.Wait();
EXPECT_TRUE(capturer.is_same_document());
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ("c", EvalJs(ftn_c, "window.state"));
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
LoadDataWithBaseURLSameDocumentNavigation) {
if (AreAllSitesIsolatedForTesting())
return;
const GURL base_url("http://baseurl");
const GURL history_url("http://history");
const std::string data = "<html><title>One</title><body>foo</body></html>";
const GURL data_url = GURL("data:text/html;charset=utf-8," + data);
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
{
TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
shell()->LoadDataWithBaseURL(history_url, data, base_url);
same_tab_observer.Wait();
}
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
EXPECT_EQ(history_url, entry->GetVirtualURL());
EXPECT_EQ(history_url, entry->GetHistoryURLForDataURL());
EXPECT_EQ(data_url, entry->GetURL());
{
TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
EXPECT_TRUE(ExecJs(shell(), "history.pushState('', 'test', '#')"));
same_tab_observer.Wait();
}
entry = controller.GetLastCommittedEntry();
EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
EXPECT_EQ(history_url, entry->GetVirtualURL());
EXPECT_EQ(history_url, entry->GetHistoryURLForDataURL());
EXPECT_EQ(data_url, entry->GetURL());
{
TestNavigationObserver back_load_observer(shell()->web_contents());
controller.GoBack();
back_load_observer.Wait();
}
entry = controller.GetLastCommittedEntry();
EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
EXPECT_EQ(history_url, entry->GetVirtualURL());
EXPECT_EQ(history_url, entry->GetHistoryURLForDataURL());
EXPECT_EQ(data_url, entry->GetURL());
EXPECT_EQ(base_url, EvalJs(shell(), "document.URL"));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
RendererInitiatedBackToLoadDataWithBaseURL) {
if (AreAllSitesIsolatedForTesting())
return;
const GURL base_url("http://baseurl");
const GURL history_url("http://history");
const std::string data = "<html><title>One</title><body>foo</body></html>";
const GURL data_url = GURL("data:text/html;charset=utf-8," + data);
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
{
TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
shell()->LoadDataWithBaseURL(history_url, data, base_url);
same_tab_observer.Wait();
}
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
EXPECT_EQ(history_url, entry->GetVirtualURL());
EXPECT_EQ(history_url, entry->GetHistoryURLForDataURL());
EXPECT_EQ(data_url, entry->GetURL());
{
TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
EXPECT_TRUE(ExecJs(shell(), "history.pushState('', 'test', '#')"));
same_tab_observer.Wait();
}
entry = controller.GetLastCommittedEntry();
EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
EXPECT_EQ(history_url, entry->GetVirtualURL());
EXPECT_EQ(history_url, entry->GetHistoryURLForDataURL());
EXPECT_EQ(data_url, entry->GetURL());
{
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "history.back()"));
capturer.Wait();
}
entry = controller.GetLastCommittedEntry();
EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
EXPECT_EQ(history_url, entry->GetVirtualURL());
EXPECT_EQ(history_url, entry->GetHistoryURLForDataURL());
EXPECT_EQ(data_url, entry->GetURL());
EXPECT_EQ(base_url, EvalJs(shell(), "document.URL"));
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
RendererInitiatedBackToLoadDataWithBaseURLDuringRestore) {
if (AreAllSitesIsolatedForTesting()) {
return;
}
const GURL base_url("http://baseurl");
const GURL history_url("http://history");
const std::string data = "<html><title>One</title><body>foo</body></html>";
const GURL data_url = GURL("data:text/html;charset=utf-8," + data);
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
{
TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
shell()->LoadDataWithBaseURL(history_url, data, base_url);
same_tab_observer.Wait();
}
GURL url2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
ASSERT_TRUE(NavigateToURL(shell(), url2));
Shell* restore_shell = Shell::CreateNewWindow(
controller.GetBrowserContext(), GURL::EmptyGURL(), nullptr, gfx::Size());
NavigationControllerImpl& restore_controller =
static_cast<NavigationControllerImpl&>(
restore_shell->web_contents()->GetController());
restore_controller.CopyStateFrom(&controller, true );
EXPECT_EQ(2, restore_controller.GetEntryCount());
EXPECT_EQ(1, restore_controller.GetLastCommittedEntryIndex());
{
TestNavigationObserver restore_observer(restore_shell->web_contents());
restore_controller.LoadIfNecessary();
restore_observer.Wait();
}
{
FrameTreeNode* root =
static_cast<WebContentsImpl*>(restore_shell->web_contents())
->GetPrimaryFrameTree()
.root();
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "history.back()"));
capturer.Wait();
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
HistoryNavigationInNewSubframe) {
DisableBackForwardCacheForTesting(contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL url1 =
embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html");
ASSERT_TRUE(NavigateToURL(shell(), url1));
GURL iframe_url = root->child_at(0)->current_url();
GURL url2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
ASSERT_TRUE(NavigateToURL(shell(), url2));
ASSERT_TRUE(controller.CanGoBack());
TestNavigationManager observer(shell()->web_contents(), iframe_url);
controller.GoBack();
EXPECT_TRUE(observer.WaitForRequestStart());
NavigationRequest* navigation = root->child_at(0)->navigation_request();
ASSERT_TRUE(navigation);
EXPECT_TRUE(navigation->IsRendererInitiated());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
HistoryNavigationInNewSubframeRendererInitiated) {
DisableBackForwardCacheForTesting(contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL url1 =
embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html");
ASSERT_TRUE(NavigateToURL(shell(), url1));
GURL iframe_url = root->child_at(0)->current_url();
GURL url2(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
ASSERT_TRUE(NavigateToURL(shell(), url2));
ASSERT_TRUE(controller.CanGoBack());
TestNavigationManager observer(shell()->web_contents(), iframe_url);
FrameNavigateParamsCapturer capturer(root);
EXPECT_TRUE(ExecJs(root, "history.back()"));
EXPECT_TRUE(observer.WaitForRequestStart());
NavigationRequest* navigation = root->child_at(0)->navigation_request();
ASSERT_TRUE(navigation);
EXPECT_TRUE(navigation->IsRendererInitiated());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, ReloadFrame) {
GURL main_url = embedded_test_server()->GetURL(
"a.com", "/frame_tree/page_with_one_frame.html");
GURL iframe_url = embedded_test_server()->GetURL("b.com", "/title1.html");
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
ASSERT_TRUE(NavigateToURL(shell(), main_url));
RenderFrameHostImpl* main_frame =
static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryMainFrame();
TestNavigationManager observer_1(shell()->web_contents(), iframe_url);
EXPECT_TRUE(ExecJs(main_frame, JsReplace(R"(
var form = document.createElement('form');
form.method = 'POST';
form.action = $1;
form.target = "child-name-0";
document.body.appendChild(form);
form.submit();
)",
iframe_url)));
EXPECT_TRUE(observer_1.WaitForRequestStart());
NavigationRequest* navigation_1 =
main_frame->child_at(0)->navigation_request();
ASSERT_TRUE(navigation_1);
EXPECT_EQ(main_url.DeprecatedGetOriginAsURL(),
navigation_1->GetReferrer().url);
EXPECT_EQ(network::mojom::ReferrerPolicy::kStrictOriginWhenCrossOrigin,
navigation_1->GetReferrer().policy);
EXPECT_TRUE(navigation_1->IsRendererInitiated());
EXPECT_TRUE(navigation_1->IsPost());
ASSERT_TRUE(observer_1.WaitForNavigationFinished());
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
NavigationEntryImpl* entry_1 = controller.GetLastCommittedEntry();
ASSERT_EQ(1U, entry_1->root_node()->children.size());
scoped_refptr<FrameNavigationEntry> frame_entry_1 =
entry_1->root_node()->children[0]->frame_entry.get();
absl::optional<url::Origin> origin_1 = frame_entry_1->initiator_origin();
ASSERT_TRUE(frame_entry_1->initiator_origin().has_value());
EXPECT_EQ(url::Origin::Create(main_url),
frame_entry_1->initiator_origin().value());
content::Referrer referrer_1 = frame_entry_1->referrer();
EXPECT_EQ(main_url.DeprecatedGetOriginAsURL(), frame_entry_1->referrer().url);
EXPECT_EQ(network::mojom::ReferrerPolicy::kStrictOriginWhenCrossOrigin,
frame_entry_1->referrer().policy);
int item_sequence_number_1 = frame_entry_1->item_sequence_number();
int document_sequence_number_1 = frame_entry_1->document_sequence_number();
TestNavigationManager observer_2(shell()->web_contents(), iframe_url);
main_frame->child_at(0)->current_frame_host()->Reload();
EXPECT_TRUE(observer_2.WaitForRequestStart());
NavigationRequest* navigation_2 =
main_frame->child_at(0)->navigation_request();
ASSERT_TRUE(navigation_2);
EXPECT_EQ(main_url.DeprecatedGetOriginAsURL(),
navigation_2->GetReferrer().url);
EXPECT_EQ(network::mojom::ReferrerPolicy::kStrictOriginWhenCrossOrigin,
navigation_2->GetReferrer().policy);
EXPECT_FALSE(navigation_2->IsRendererInitiated());
EXPECT_TRUE(navigation_2->IsPost());
ASSERT_TRUE(observer_2.WaitForNavigationFinished());
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
NavigationEntryImpl* entry_2 = controller.GetLastCommittedEntry();
ASSERT_EQ(1U, entry_1->root_node()->children.size());
scoped_refptr<FrameNavigationEntry> frame_entry_2 =
entry_2->root_node()->children[0]->frame_entry.get();
absl::optional<url::Origin> origin_2 = frame_entry_2->initiator_origin();
ASSERT_TRUE(frame_entry_2->initiator_origin().has_value());
EXPECT_EQ(url::Origin::Create(main_url),
frame_entry_2->initiator_origin().value());
content::Referrer referrer_2 = frame_entry_1->referrer();
EXPECT_EQ(main_url.DeprecatedGetOriginAsURL(), frame_entry_2->referrer().url);
EXPECT_EQ(network::mojom::ReferrerPolicy::kStrictOriginWhenCrossOrigin,
frame_entry_2->referrer().policy);
int item_sequence_number_2 = frame_entry_1->item_sequence_number();
int document_sequence_number_2 = frame_entry_1->document_sequence_number();
EXPECT_EQ(item_sequence_number_1, item_sequence_number_2);
EXPECT_EQ(document_sequence_number_1, document_sequence_number_2);
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
HistoryNavigationDoesntMoveFrameWithoutCommit) {
WebContents* wc = shell()->web_contents();
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(wc->GetController());
GURL main_url = embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a,a)");
EXPECT_TRUE(NavigateToURL(shell(), main_url));
RenderFrameHostImpl* main_frame =
static_cast<RenderFrameHostImpl*>(wc->GetPrimaryMainFrame());
FrameTreeNode* b_frame = main_frame->child_at(0);
FrameTreeNode* c_frame = main_frame->child_at(1);
ASSERT_TRUE(b_frame);
ASSERT_TRUE(c_frame);
{
LoadCommittedCapturer capturer(wc);
EXPECT_TRUE(ExecJs(c_frame, kAddEmptyFrameScript));
capturer.Wait();
}
FrameTreeNode* cc_frame = c_frame->current_frame_host()->child_at(0);
ASSERT_TRUE(cc_frame);
const char set_status_on_beforeunload[] = R"(
window.top.testStatus = "STARTED";
window.addEventListener(
"beforeunload",
() => { window.top.testStatus = "UNLOAD" },
false);
window.top.testStatus;
)";
EXPECT_EQ("STARTED",
EvalJs(cc_frame, set_status_on_beforeunload).ExtractString());
GURL url2 = embedded_test_server()->GetURL("a.com", "/title2.html");
EXPECT_TRUE(NavigateToURLFromRenderer(b_frame, url2));
EXPECT_FALSE(cc_frame->current_frame_host()->has_committed_any_navigation());
scoped_refptr<FrameNavigationEntry> b_entry =
controller.GetLastCommittedEntry()->GetFrameEntry(b_frame);
int64_t b_isn = b_entry->item_sequence_number();
FrameNavigateParamsCapturer capturer(b_frame);
controller.GoBack();
capturer.Wait();
scoped_refptr<FrameNavigationEntry> b2_entry =
controller.GetLastCommittedEntry()->GetFrameEntry(b_frame);
int64_t b2_isn = b2_entry->item_sequence_number();
EXPECT_NE(b_isn, b2_isn);
EXPECT_FALSE(cc_frame->current_frame_host()->has_committed_any_navigation());
const char set_status_done[] = R"(
if (window.top.testStatus == "STARTED")
window.top.testStatus = "DONE";
window.top.testStatus;
)";
EXPECT_EQ("DONE", EvalJs(cc_frame, set_status_done).ExtractString());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
OverrideUserAgentThenReload) {
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL("a.com", "/empty.html")));
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
controller.GetLastCommittedEntry()->SetIsOverridingUserAgent(true);
EXPECT_TRUE(controller.GetLastCommittedEntry()->GetIsOverridingUserAgent());
controller.Reload(ReloadType::ORIGINAL_REQUEST_URL, true);
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_TRUE(controller.GetLastCommittedEntry()->GetIsOverridingUserAgent());
EXPECT_TRUE(ExecJs(shell(), "history.pushState('', 'test', '#foo2')"));
EXPECT_TRUE(controller.GetLastCommittedEntry()->GetIsOverridingUserAgent());
EXPECT_TRUE(ExecJs(shell(), "location.href = '/title1.html';"));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_TRUE(controller.GetLastCommittedEntry()->GetIsOverridingUserAgent());
EXPECT_TRUE(ExecJs(
shell(), JsReplace("location.href = $1;", embedded_test_server()->GetURL(
"b.com", "/empty.html"))));
EXPECT_TRUE(controller.GetLastCommittedEntry()->GetIsOverridingUserAgent());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
OverrideUserAgentThenSameDocument) {
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL("a.com", "/empty.html")));
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
controller.GetLastCommittedEntry()->SetIsOverridingUserAgent(true);
EXPECT_TRUE(controller.GetLastCommittedEntry()->GetIsOverridingUserAgent());
EXPECT_TRUE(ExecJs(shell(), "history.pushState('', 'test', '#foo1')"));
EXPECT_FALSE(controller.GetLastCommittedEntry()->GetIsOverridingUserAgent());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
URLLoadReturnsNavigationHandle) {
GURL url(embedded_test_server()->GetURL("/title1.html"));
TestNavigationManager navigation_manager(shell()->web_contents(), url);
base::WeakPtr<NavigationHandle> navigation =
shell()->web_contents()->GetController().LoadURLWithParams(
NavigationController::LoadURLParams(url));
EXPECT_TRUE(navigation);
ASSERT_TRUE(navigation_manager.WaitForRequestStart());
EXPECT_TRUE(navigation);
EXPECT_EQ(navigation->GetNavigationId(),
navigation_manager.GetNavigationHandle()->GetNavigationId());
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_FALSE(navigation);
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, FilterAbout) {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL("a.com", "/empty.html")));
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_TRUE(NavigateToURLFromRenderer(shell(), GURL("about:cache"),
GURL(kBlockedURL)));
EXPECT_EQ(2, controller.GetEntryCount());
ASSERT_TRUE(controller.GetVisibleEntry());
EXPECT_EQ(GURL(kBlockedURL), controller.GetVisibleEntry()->GetURL());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, WindowReload) {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
EXPECT_EQ(1, controller.GetEntryCount());
TestNavigationObserver observer(contents());
EXPECT_TRUE(ExecJs(current_main_frame_host(), "window.location.reload();"));
observer.WaitForNavigationFinished();
EXPECT_NE(0, observer.last_nav_entry_id());
EXPECT_EQ(1, controller.GetEntryCount());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, WindowReloadInIframe) {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
EXPECT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL(
"a.com", "/page_with_iframe.html")));
EXPECT_EQ(1, controller.GetEntryCount());
TestNavigationObserver observer(contents());
EXPECT_TRUE(ExecJs(current_main_frame_host()->child_at(0),
"window.location.reload();"));
observer.WaitForNavigationFinished();
EXPECT_EQ(0, observer.last_nav_entry_id());
EXPECT_EQ(1, controller.GetEntryCount());
}
namespace {
class AllNavigationStateChangedDelegate : public WebContentsDelegate {
public:
AllNavigationStateChangedDelegate() = default;
AllNavigationStateChangedDelegate(const AllNavigationStateChangedDelegate&) =
delete;
AllNavigationStateChangedDelegate& operator=(
const AllNavigationStateChangedDelegate&) = delete;
~AllNavigationStateChangedDelegate() override = default;
void NavigationStateChanged(WebContents* source,
InvalidateTypes changed_flags) override {
if (changed_flags == INVALIDATE_TYPE_ALL)
call_count_++;
}
int call_count() { return call_count_; }
private:
int call_count_ = 0;
};
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
RelativeURLInAboutBlankPopup) {
GURL url1 = embedded_test_server()->GetURL("/title1.html");
EXPECT_TRUE(NavigateToURL(shell(), url1));
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
ShellAddedObserver new_shell_observer;
EXPECT_TRUE(ExecJs(root, "var w = window.open()"));
Shell* new_shell = new_shell_observer.GetShell();
WebContentsImpl* new_contents =
static_cast<WebContentsImpl*>(new_shell->web_contents());
EXPECT_TRUE(WaitForLoadStop(new_contents));
AllNavigationStateChangedDelegate all_navigation_state_changed_delegate;
new_contents->SetDelegate(&all_navigation_state_changed_delegate);
EXPECT_EQ(0, all_navigation_state_changed_delegate.call_count());
ASSERT_NE(new_contents, shell()->web_contents());
FrameTreeNode* new_root = new_contents->GetPrimaryFrameTree().root();
NavigationControllerImpl& controller = new_contents->GetController();
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_TRUE(controller.GetLastCommittedEntry()->IsInitialEntry());
if (blink::features::IsNewBaseUrlInheritanceBehaviorEnabled()) {
EXPECT_NE("about:blank",
EvalJs(new_root, "document.baseURI").ExtractString());
} else {
EXPECT_EQ("about:blank",
EvalJs(new_root, "document.baseURI").ExtractString());
}
FrameNavigateParamsCapturer capturer(new_root);
EXPECT_TRUE(ExecJs(new_root, "location.href = '#foo';"));
capturer.Wait();
if (blink::features::IsNewBaseUrlInheritanceBehaviorEnabled()) {
EXPECT_EQ(embedded_test_server()->GetURL("/title1.html#foo"),
new_root->current_url());
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_FALSE(capturer.is_same_document());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_FALSE(controller.GetLastCommittedEntry()->IsInitialEntry());
} else {
EXPECT_EQ(GURL("about:blank#foo"), new_root->current_url());
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_TRUE(controller.GetLastCommittedEntry()->IsInitialEntry());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
NavigationStateChangedForInitialNavigationEntry) {
GURL url1 = embedded_test_server()->GetURL("/title1.html");
GURL url2 = embedded_test_server()->GetURL("/title2.html");
EXPECT_TRUE(NavigateToURL(shell(), url1));
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
ShellAddedObserver new_shell_observer;
EXPECT_TRUE(ExecJs(root, "var w = window.open()"));
Shell* new_shell = new_shell_observer.GetShell();
WebContentsImpl* new_contents =
static_cast<WebContentsImpl*>(new_shell->web_contents());
EXPECT_TRUE(WaitForLoadStop(new_contents));
AllNavigationStateChangedDelegate all_navigation_state_changed_delegate;
new_contents->SetDelegate(&all_navigation_state_changed_delegate);
EXPECT_EQ(0, all_navigation_state_changed_delegate.call_count());
ASSERT_NE(new_contents, shell()->web_contents());
FrameTreeNode* new_root = new_contents->GetPrimaryFrameTree().root();
NavigationControllerImpl& controller = new_contents->GetController();
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_TRUE(controller.GetLastCommittedEntry()->IsInitialEntry());
{
LoadCommittedCapturer capturer(new_contents);
std::string script = JsReplace(kAddFrameWithSrcScript, url1);
EXPECT_TRUE(ExecJs(new_root, script));
capturer.Wait();
EXPECT_EQ(url1, new_root->child_at(0)->current_url());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_TRUE(controller.GetLastCommittedEntry()->IsInitialEntry());
EXPECT_EQ(0, all_navigation_state_changed_delegate.call_count());
}
{
FrameNavigateParamsCapturer capturer(new_root->child_at(0));
NavigateFrameToURL(new_root->child_at(0), url2);
capturer.Wait();
EXPECT_EQ(url2, new_root->child_at(0)->current_url());
EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.navigation_type());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_TRUE(controller.GetLastCommittedEntry()->IsInitialEntry());
EXPECT_EQ(0, all_navigation_state_changed_delegate.call_count());
}
{
FrameNavigateParamsCapturer capturer(new_root);
EXPECT_TRUE(ExecJs(new_root, "location.href = 'about:blank#foo';"));
capturer.Wait();
EXPECT_EQ(GURL("about:blank#foo"), new_root->current_url());
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_EXISTING_ENTRY,
capturer.navigation_type());
EXPECT_TRUE(capturer.is_same_document());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_TRUE(controller.GetLastCommittedEntry()->IsInitialEntry());
EXPECT_EQ(2, all_navigation_state_changed_delegate.call_count());
}
{
FrameNavigateParamsCapturer capturer(new_root);
EXPECT_TRUE(ExecJs(new_root, JsReplace("location.href = $1;", url2)));
capturer.Wait();
EXPECT_EQ(url2, new_root->current_url());
EXPECT_EQ(NAVIGATION_TYPE_MAIN_FRAME_NEW_ENTRY, capturer.navigation_type());
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_FALSE(controller.GetLastCommittedEntry()->IsInitialEntry());
EXPECT_EQ(4, all_navigation_state_changed_delegate.call_count());
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
RestoreRemovesInitialEmptyDocumentOnFreshNavigationController) {
GURL url_1(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url_2(embedded_test_server()->GetURL("a.com", "/title2.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_1));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(url_1, root->current_url());
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
NavigationEntryImpl* entry1 = controller.GetLastCommittedEntry();
std::unique_ptr<NavigationEntryImpl> restored_entry =
NavigationEntryImpl::FromNavigationEntry(
NavigationController::CreateNavigationEntry(
url_1, Referrer(), absl::nullopt ,
absl::nullopt,
ui::PAGE_TRANSITION_RELOAD, false, std::string(),
controller.GetBrowserContext(),
nullptr ));
EXPECT_EQ(0U, restored_entry->root_node()->children.size());
std::unique_ptr<NavigationEntryRestoreContextImpl> context =
std::make_unique<NavigationEntryRestoreContextImpl>();
restored_entry->SetPageState(entry1->GetPageState(), context.get());
std::vector<std::unique_ptr<NavigationEntry>> entries;
entries.push_back(std::move(restored_entry));
Shell* new_shell = Shell::CreateNewWindow(
controller.GetBrowserContext(), GURL::EmptyGURL(), nullptr, gfx::Size());
FrameTreeNode* new_root =
static_cast<WebContentsImpl*>(new_shell->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& new_controller =
static_cast<NavigationControllerImpl&>(
new_shell->web_contents()->GetController());
EXPECT_TRUE(new_root->is_on_initial_empty_document());
EXPECT_TRUE(new_controller.GetLastCommittedEntry()->IsInitialEntry());
new_controller.Restore(entries.size() - 1, RestoreType::kRestored, &entries);
EXPECT_EQ(0u, entries.size());
EXPECT_EQ(1, new_controller.GetEntryCount());
EXPECT_TRUE(new_root->is_on_initial_empty_document());
EXPECT_FALSE(new_controller.GetLastCommittedEntry()->IsInitialEntry());
FrameNavigateParamsCapturer capturer(new_root);
EXPECT_TRUE(NavigateToURL(new_shell, url_2));
capturer.Wait();
EXPECT_FALSE(capturer.did_replace_entry());
EXPECT_EQ(2, new_controller.GetEntryCount());
EXPECT_EQ(url_1, new_controller.GetEntryAtIndex(0)->GetURL());
EXPECT_EQ(url_2, new_controller.GetLastCommittedEntry()->GetURL());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
RestoreEmptyAndLoadOnFreshNavigationController) {
Shell* new_shell =
Shell::CreateNewWindow(shell()->web_contents()->GetBrowserContext(),
GURL::EmptyGURL(), nullptr, gfx::Size());
FrameTreeNode* new_root =
static_cast<WebContentsImpl*>(new_shell->web_contents())
->GetPrimaryFrameTree()
.root();
NavigationControllerImpl& new_controller =
static_cast<NavigationControllerImpl&>(
new_shell->web_contents()->GetController());
EXPECT_EQ(1, new_controller.GetEntryCount());
EXPECT_EQ(0, new_controller.GetLastCommittedEntryIndex());
EXPECT_TRUE(new_controller.GetLastCommittedEntry()->IsInitialEntry());
std::vector<std::unique_ptr<NavigationEntry>> entries;
new_controller.Restore(-1, RestoreType::kRestored, &entries);
EXPECT_EQ(1, new_controller.GetEntryCount());
EXPECT_EQ(0, new_controller.GetLastCommittedEntryIndex());
EXPECT_TRUE(new_controller.GetLastCommittedEntry()->IsInitialEntry());
ASSERT_EQ(0u, entries.size());
new_controller.LoadIfNecessary();
EXPECT_FALSE(new_root->navigation_request());
EXPECT_EQ(nullptr, new_controller.GetPendingEntry());
FrameNavigateParamsCapturer capturer(new_root);
GURL url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(new_shell, url));
capturer.Wait();
EXPECT_TRUE(capturer.did_replace_entry());
EXPECT_EQ(1, new_controller.GetEntryCount());
EXPECT_EQ(url, new_controller.GetLastCommittedEntry()->GetURL());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
ResetForTestForcesNewBrowsingInstance) {
GURL test_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), test_url));
SiteInstance* initial_site_instance = contents()->GetSiteInstance();
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
DisableProactiveBrowsingInstanceSwapFor(root->current_frame_host());
TestNavigationObserver navigation_observer(contents());
NavigationController::LoadURLParams params(test_url);
params.force_new_browsing_instance = true;
contents()->GetController().LoadURLWithParams(params);
navigation_observer.Wait();
EXPECT_TRUE(navigation_observer.last_navigation_succeeded());
SiteInstance* post_reset_site_instance = contents()->GetSiteInstance();
EXPECT_NE(initial_site_instance, post_reset_site_instance);
EXPECT_FALSE(
post_reset_site_instance->IsRelatedSiteInstance(initial_site_instance));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, UnloadTiming) {
DisableBackForwardCacheForTesting(contents(),
BackForwardCache::TEST_USES_UNLOAD_EVENT);
GURL initial_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html"));
EXPECT_TRUE(NavigateToURL(shell(), initial_url));
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
ASSERT_EQ(1u, root->child_count());
FrameTreeNode* child = root->child_at(0u);
ASSERT_TRUE(NavigateFrameToURL(child, url_a));
EXPECT_TRUE(ExecJs(
child,
"var navigationTiming = performance.getEntriesByType('navigation')"));
ASSERT_EQ(1, EvalJs(child, "navigationTiming.length"));
EXPECT_NE(0, EvalJs(child, "navigationTiming[0].unloadEventStart"));
EXPECT_NE(0, EvalJs(child, "navigationTiming[0].unloadEventEnd"));
{
FrameNavigateParamsCapturer capturer(child);
ASSERT_TRUE(NavigateFrameToURL(child, url_b));
capturer.Wait();
}
EXPECT_TRUE(ExecJs(
child,
"var navigationTiming = performance.getEntriesByType('navigation')"));
ASSERT_EQ(1, EvalJs(child, "navigationTiming.length"));
EXPECT_EQ(0, EvalJs(child, "navigationTiming[0].unloadEventStart"));
EXPECT_EQ(0, EvalJs(child, "navigationTiming[0].unloadEventEnd"));
ASSERT_TRUE(NavigateToURL(shell(), url_a));
EXPECT_TRUE(ExecJs(
root,
"var navigationTiming = performance.getEntriesByType('navigation')"));
ASSERT_EQ(1, EvalJs(root, "navigationTiming.length"));
EXPECT_NE(0, EvalJs(root, "navigationTiming[0].unloadEventStart"));
EXPECT_NE(0, EvalJs(root, "navigationTiming[0].unloadEventEnd"));
ASSERT_TRUE(NavigateToURL(shell(), url_b));
EXPECT_TRUE(ExecJs(
root,
"var navigationTiming = performance.getEntriesByType('navigation')"));
ASSERT_EQ(1, EvalJs(root, "navigationTiming.length"));
EXPECT_EQ(0, EvalJs(root, "navigationTiming[0].unloadEventStart"));
EXPECT_EQ(0, EvalJs(root, "navigationTiming[0].unloadEventEnd"));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
SameURLNavigationRetainsHistoryState) {
GURL main_frame_url(embedded_test_server()->GetURL("/page_with_iframe.html"));
GURL subframe_url(embedded_test_server()->GetURL("/title1.html"));
GURL other_url(embedded_test_server()->GetURL("/title2.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_frame_url));
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
ASSERT_EQ(1u, root->child_count());
FrameTreeNode* child = root->child_at(0u);
EXPECT_EQ(main_frame_url, root->current_url());
EXPECT_EQ(subframe_url, child->current_url());
ReplaceState(child, "foo");
{
FrameNavigateParamsCapturer capturer(child);
ASSERT_TRUE(NavigateFrameToURL(child, subframe_url));
capturer.Wait();
EXPECT_EQ(subframe_url, child->current_url());
}
EXPECT_EQ("foo", EvalJs(child, "history.state"));
{
FrameNavigateParamsCapturer capturer(child);
ASSERT_TRUE(NavigateFrameToURL(child, other_url));
capturer.Wait();
EXPECT_EQ(other_url, child->current_url());
}
EXPECT_EQ(nullptr, EvalJs(child, "history.state"));
ReplaceState(root, "bar");
EXPECT_EQ("bar", EvalJs(root, "history.state"));
ASSERT_TRUE(NavigateToURL(shell(), GURL(root->current_url())));
EXPECT_EQ("bar", EvalJs(root, "history.state"));
ASSERT_TRUE(NavigateToURL(shell(), other_url));
EXPECT_EQ(nullptr, EvalJs(root, "history.state"));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
GoForwardAfterInitialHistoryInChildFrame) {
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/page_with_iframe.html"));
ASSERT_TRUE(NavigateToURL(shell(), main_url));
NavigationControllerImpl& controller = contents()->GetController();
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child = root->child_at(0);
GURL subframe_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
{
TestNavigationObserver navigation_observer(contents());
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), subframe_url));
navigation_observer.Wait();
}
{
TestNavigationObserver navigation_observer(contents());
std::string script = "location.href = '#foo';";
EXPECT_TRUE(ExecJs(child, script));
navigation_observer.Wait();
}
GURL child_url(child->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
GURL cross_doc_url(embedded_test_server()->GetURL("a.com", "/title2.html"));
{
TestNavigationObserver navigation_observer(contents());
EXPECT_TRUE(NavigateToURLFromRenderer(root, cross_doc_url));
navigation_observer.Wait();
}
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetCurrentEntryIndex());
{
TestNavigationObserver navigation_observer(contents());
controller.GoToOffset(-2);
navigation_observer.Wait();
}
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetCurrentEntryIndex());
{
TestNavigationObserver navigation_observer(shell()->web_contents());
controller.GoForward();
navigation_observer.Wait();
}
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
EXPECT_EQ(child_url,
root->child_at(0)->current_frame_host()->GetLastCommittedURL());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
GoBackInMultipleIframesOneFastOneSlow) {
GURL main_url = embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b,c)");
ASSERT_TRUE(NavigateToURL(shell(), main_url));
NavigationControllerImpl& controller = contents()->GetController();
FrameTreeNode* ftn_a = contents()->GetPrimaryFrameTree().root();
FrameTreeNode* ftn_b = ftn_a->child_at(0);
FrameTreeNode* ftn_c = ftn_a->child_at(1);
GURL url_b(ftn_b->current_frame_host()->GetLastCommittedURL());
GURL url_c(ftn_c->current_frame_host()->GetLastCommittedURL());
{
TestNavigationObserver navigation_observer(shell()->web_contents());
std::string script = "location.href = '#foo';";
EXPECT_TRUE(ExecJs(ftn_c, script));
navigation_observer.Wait();
}
EXPECT_EQ(2, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
GURL url_b2(embedded_test_server()->GetURL("a.com", "/title2.html"));
{
TestNavigationObserver navigation_observer(contents());
EXPECT_TRUE(NavigateToURLFromRenderer(ftn_b, url_b2));
navigation_observer.Wait();
}
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(2, controller.GetCurrentEntryIndex());
EXPECT_EQ(url_b2, ftn_b->current_frame_host()->GetLastCommittedURL());
GURL url_c2(embedded_test_server()->GetURL("a.com", "/title2.html"));
{
TestNavigationObserver navigation_observer(contents());
EXPECT_TRUE(NavigateToURLFromRenderer(ftn_c, url_c2));
navigation_observer.Wait();
}
EXPECT_EQ(4, controller.GetEntryCount());
EXPECT_EQ(3, controller.GetCurrentEntryIndex());
EXPECT_EQ(url_c2, ftn_c->current_frame_host()->GetLastCommittedURL());
FrameTestNavigationManager b_delayer(ftn_b->frame_tree_node_id(),
shell()->web_contents(), url_b);
FrameTestNavigationManager c_delayer(ftn_c->frame_tree_node_id(),
shell()->web_contents(), url_c);
controller.GoToOffset(-3);
ASSERT_TRUE(b_delayer.WaitForNavigationFinished());
ASSERT_TRUE(c_delayer.WaitForNavigationFinished());
EXPECT_TRUE(WaitForLoadStop(contents()));
EXPECT_EQ(4, controller.GetEntryCount());
EXPECT_EQ(0, controller.GetCurrentEntryIndex());
EXPECT_EQ(url_b, ftn_b->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ(url_c, ftn_c->current_frame_host()->GetLastCommittedURL());
{
TestNavigationObserver navigation_observer(shell()->web_contents());
controller.GoForward();
navigation_observer.Wait();
}
EXPECT_EQ(4, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
DeleteNavigationEntriesFiresNavigationApiDisposeEvent) {
GURL url1 = embedded_test_server()->GetURL("a.com", "/title1.html");
GURL url2(embedded_test_server()->GetURL("a.com", "/title2.html"));
GURL url3(embedded_test_server()->GetURL("a.com", "/title3.html"));
ASSERT_TRUE(NavigateToURL(shell(), url1));
ASSERT_TRUE(NavigateToURL(shell(), url2));
ASSERT_TRUE(NavigateToURL(shell(), url3));
NavigationControllerImpl& controller = contents()->GetController();
TestNavigationObserver back_load_observer(shell()->web_contents());
controller.GoBack();
back_load_observer.Wait();
EXPECT_EQ(3, controller.GetEntryCount());
EXPECT_EQ(1, controller.GetCurrentEntryIndex());
EXPECT_TRUE(ExecJs(contents(), R"(
window.dispose0_fired = false;
window.dispose1_fired = false;
window.dispose2_fired = false;
navigation.entries()[0].ondispose = () => window.dispose0_fired = true;
navigation.entries()[1].ondispose = () => window.dispose2_fired = true;
navigation.entries()[2].ondispose = () => window.dispose2_fired = true;
)"));
controller.DeleteNavigationEntries(
base::BindLambdaForTesting([&](content::NavigationEntry* entry) {
return entry->GetURL() == url1;
}));
EXPECT_EQ(true, EvalJs(shell(), "window.dispose0_fired").ExtractBool());
EXPECT_EQ(false, EvalJs(shell(), "window.dispose1_fired").ExtractBool());
EXPECT_EQ(false, EvalJs(shell(), "window.dispose2_fired").ExtractBool());
controller.DeleteNavigationEntries(
base::BindLambdaForTesting([&](content::NavigationEntry* entry) {
return entry->GetURL() == url3;
}));
EXPECT_EQ(true, EvalJs(shell(), "window.dispose0_fired").ExtractBool());
EXPECT_EQ(false, EvalJs(shell(), "window.dispose1_fired").ExtractBool());
EXPECT_EQ(true, EvalJs(shell(), "window.dispose2_fired").ExtractBool());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
NavigationApiTraverseCancelledByRaceCondition) {
GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url2(embedded_test_server()->GetURL("a.com", "/title2.html"));
EXPECT_TRUE(NavigateToURL(contents(), url1));
EXPECT_TRUE(NavigateToURL(contents(), url2));
ExecuteScriptAsync(contents()->GetPrimaryFrameTree().root(),
"navigation.back().committed.then("
"() => document.title = 'FAIL',"
"e => document.title = e.name === 'InvalidStateError'"
" ? 'PASS' : 'WRONG_ERROR_TYPE');");
contents()->GetController().PruneAllButLastCommitted();
TitleWatcher title_watcher(shell()->web_contents(), u"PASS");
EXPECT_EQ(u"PASS", title_watcher.WaitAndGetTitle());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
NavigationApiBackSameOriginDifferentSiteInstance) {
GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url2(embedded_test_server()->GetURL("a.com", "/title2.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
scoped_refptr<SiteInstance> initial_site_instance =
contents()->GetSiteInstance();
TestNavigationObserver navigation_observer(contents());
NavigationController::LoadURLParams params(url2);
params.force_new_browsing_instance = true;
controller.LoadURLWithParams(params);
navigation_observer.Wait();
EXPECT_TRUE(navigation_observer.last_navigation_succeeded());
EXPECT_NE(initial_site_instance, contents()->GetSiteInstance());
EXPECT_TRUE(EvalJs(shell(), "navigation.canGoBack").ExtractBool());
TestNavigationObserver navigation_observer2(contents());
ExecuteScriptAsync(contents()->GetPrimaryFrameTree().root(),
"navigation.back()");
navigation_observer2.Wait();
EXPECT_EQ(url1, controller.GetLastCommittedEntry()->GetURL());
EXPECT_EQ(initial_site_instance, contents()->GetSiteInstance());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTestNoServer,
RendererInitiatedCancellationDueToJS) {
net::test_server::ControllableHttpResponse fetch_response(
embedded_test_server(), "/fetch");
ASSERT_TRUE(embedded_test_server()->Start());
GURL url1(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
EXPECT_TRUE(NavigateToURL(contents(), url1));
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child = root->child_at(0);
GURL child_url = child->current_url();
GURL child_url_2(embedded_test_server()->GetURL("a.com", "/title1.html"));
TestNavigationManager nav_manager(contents(), child_url_2);
ExecuteScriptAsync(child, R"(
location.href = '/title1.html';
var request = new XMLHttpRequest();
request.open("GET", "/fetch", /*async=*/false);
request.send("");
var fetch_success = (request.readyState == 4 && request.status == 200);
window.stop();
)");
EXPECT_TRUE(nav_manager.WaitForRequestStart());
nav_manager.ResumeNavigation();
NavigationRequest* request =
static_cast<NavigationRequest*>(nav_manager.GetNavigationHandle());
EXPECT_EQ(request, child->navigation_request());
base::RunLoop run_loop;
NavigationThrottleRunner* throttle_runner =
request->GetNavigationThrottleRunnerForTesting();
throttle_runner->set_first_deferral_callback_for_testing(
run_loop.QuitClosure());
run_loop.Run();
EXPECT_TRUE(request->IsDeferredForTesting());
EXPECT_STREQ("RendererCancellationThrottle",
throttle_runner->GetDeferringThrottle()->GetNameForLogging());
EXPECT_EQ(request->state(), NavigationRequest::WILL_PROCESS_RESPONSE);
fetch_response.WaitForRequest();
fetch_response.Send(net::HTTP_OK, "foo");
fetch_response.Done();
ASSERT_TRUE(nav_manager.WaitForNavigationFinished());
EXPECT_FALSE(nav_manager.was_successful());
EXPECT_EQ(child_url, child->current_url());
EXPECT_EQ(true, EvalJs(child, "fetch_success"));
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTestNoServer,
RendererInitiatedCancellationDueToCrash) {
net::test_server::ControllableHttpResponse fetch_response(
embedded_test_server(), "/fetch");
ASSERT_TRUE(embedded_test_server()->Start());
GURL url1(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(contents(), url1));
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child = root->child_at(0);
GURL child_url = child->current_url();
GURL child_url_2(embedded_test_server()->GetURL("b.com", "/title1.html"));
TestNavigationManager nav_manager(contents(), child_url_2);
ExecuteScriptAsync(child, R"(
location.href = '/title1.html';
var request = new XMLHttpRequest();
request.open("GET", "/fetch", /*async=*/false);
request.send("");
var fetch_success = (request.readyState == 4 && request.status == 200);
window.stop();
)");
EXPECT_TRUE(nav_manager.WaitForRequestStart());
nav_manager.ResumeNavigation();
NavigationRequest* request =
static_cast<NavigationRequest*>(nav_manager.GetNavigationHandle());
EXPECT_EQ(request, child->navigation_request());
base::RunLoop run_loop;
NavigationThrottleRunner* throttle_runner =
request->GetNavigationThrottleRunnerForTesting();
throttle_runner->set_first_deferral_callback_for_testing(
run_loop.QuitClosure());
run_loop.Run();
EXPECT_TRUE(request->IsDeferredForTesting());
EXPECT_STREQ("RendererCancellationThrottle",
throttle_runner->GetDeferringThrottle()->GetNameForLogging());
EXPECT_EQ(request->state(), NavigationRequest::WILL_PROCESS_RESPONSE);
RenderProcessHost* child_process = child->current_frame_host()->GetProcess();
RenderProcessHostWatcher crash_observer(
child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
child_process->Shutdown(0);
crash_observer.Wait();
ASSERT_TRUE(nav_manager.WaitForNavigationFinished());
EXPECT_FALSE(nav_manager.was_successful());
if (AreAllSitesIsolatedForTesting())
EXPECT_EQ(GURL(), child->current_url());
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTestNoServer,
RendererInitiatedCancellationTimeoutWarnsUnresponsiveRenderer) {
net::test_server::ControllableHttpResponse fetch_response(
embedded_test_server(), "/fetch");
ASSERT_TRUE(embedded_test_server()->Start());
GURL url1(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(contents(), url1));
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child = root->child_at(0);
GURL child_url = child->current_url();
GURL child_url_2(embedded_test_server()->GetURL("b.com", "/title1.html"));
RendererCancellationThrottle::SetCancellationTimeoutForTesting(
base::Milliseconds(100));
UnresponsiveRendererObserver unresponsive_renderer_observer(contents());
TestNavigationManager nav_manager(contents(), child_url_2);
ExecuteScriptAsync(child, R"(
location.href = '/title1.html';
var request = new XMLHttpRequest();
request.open("GET", "/fetch", /*async=*/false);
request.send("");
var fetch_success = (request.readyState == 4 && request.status == 200);
window.stop();
)");
EXPECT_TRUE(nav_manager.WaitForRequestStart());
nav_manager.ResumeNavigation();
NavigationRequest* request =
static_cast<NavigationRequest*>(nav_manager.GetNavigationHandle());
EXPECT_EQ(request, child->navigation_request());
base::RunLoop run_loop;
NavigationThrottleRunner* throttle_runner =
request->GetNavigationThrottleRunnerForTesting();
throttle_runner->set_first_deferral_callback_for_testing(
run_loop.QuitClosure());
run_loop.Run();
EXPECT_TRUE(request->IsDeferredForTesting());
EXPECT_STREQ("RendererCancellationThrottle",
throttle_runner->GetDeferringThrottle()->GetNameForLogging());
EXPECT_EQ(request->state(), NavigationRequest::WILL_PROCESS_RESPONSE);
RenderProcessHost* hung_process = unresponsive_renderer_observer.Wait();
EXPECT_EQ(hung_process, child->current_frame_host()->GetProcess());
EXPECT_TRUE(request->IsDeferredForTesting());
RendererCancellationThrottle::SetCancellationTimeoutForTesting(
base::TimeDelta());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTestNoServer,
HistoryNavigationToPreviouslySandboxedDocument) {
net::test_server::ControllableHttpResponse response1(
embedded_test_server(), "/sandboxed_on_first_load_only");
net::test_server::ControllableHttpResponse response2(
embedded_test_server(), "/sandboxed_on_first_load_only");
ASSERT_TRUE(embedded_test_server()->Start());
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
FrameTreeNode* root =
static_cast<WebContentsImpl*>(contents())->GetPrimaryFrameTree().root();
GURL main_url(
embedded_test_server()->GetURL("a.com", "/sandboxed_on_first_load_only"));
{
TestNavigationObserver nav_observer(contents());
shell()->LoadURL(main_url);
response1.WaitForRequest();
response1.Send(
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"Content-Security-Policy: sandbox\r\n"
"Cache-Control: no-store\r\n"
"\r\n"
"sandboxed document");
response1.Done();
nav_observer.Wait();
EXPECT_EQ(main_url, controller.GetLastCommittedEntry()->GetURL());
EXPECT_TRUE(root->current_frame_host()->IsSandboxed(
network::mojom::WebSandboxFlags::kAll));
EXPECT_TRUE(root->current_frame_host()->GetLastCommittedOrigin().opaque());
EXPECT_TRUE(
root->current_frame_host()->GetLastCommittedOrigin().CanBeDerivedFrom(
main_url));
}
{
TestNavigationObserver back_load_observer(contents());
GURL url_2(embedded_test_server()->GetURL("b.com", "/title2.html"));
shell()->LoadURL(url_2);
back_load_observer.Wait();
EXPECT_EQ(url_2, controller.GetLastCommittedEntry()->GetURL());
}
{
TestNavigationObserver nav_observer(contents());
controller.GoBack();
response2.WaitForRequest();
response2.Send(
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"\r\n"
"non-sandboxed document");
response2.Done();
nav_observer.Wait();
EXPECT_EQ(main_url, controller.GetLastCommittedEntry()->GetURL());
EXPECT_FALSE(root->current_frame_host()->IsSandboxed(
network::mojom::WebSandboxFlags::kAll));
EXPECT_FALSE(root->current_frame_host()->GetLastCommittedOrigin().opaque());
EXPECT_EQ(root->current_frame_host()->GetLastCommittedOrigin(),
url::Origin::Create(main_url));
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
HistoryNavigationToPreviouslySandboxedDocumentOnIframe) {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
GURL main_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root =
static_cast<WebContentsImpl*>(contents())->GetPrimaryFrameTree().root();
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, R"(
let iframe = document.createElement('iframe');
iframe.id = 'child';
iframe.src = location.href;
document.body.appendChild(iframe);)"));
capturer.Wait();
}
FrameTreeNode* child = root->child_at(0);
{
FrameNavigateParamsCapturer capturer(child);
EXPECT_TRUE(ExecJs(root, R"(
document.getElementById('child').setAttribute('sandbox', '');
document.getElementById('child').src = 'about:blank';)"));
capturer.Wait();
EXPECT_TRUE(child->current_frame_host()->IsSandboxed(
network::mojom::WebSandboxFlags::kAll));
EXPECT_TRUE(child->current_frame_host()->GetLastCommittedOrigin().opaque());
EXPECT_TRUE(
child->current_frame_host()->GetLastCommittedOrigin().CanBeDerivedFrom(
main_url));
}
{
GURL url_2(embedded_test_server()->GetURL("b.com", "/title2.html"));
FrameNavigateParamsCapturer capturer(child);
NavigateFrameToURL(child, url_2);
capturer.Wait();
}
{
EXPECT_TRUE(ExecJs(
root, "document.getElementById('child').removeAttribute('sandbox');"));
FrameNavigateParamsCapturer capturer(child);
controller.GoBack();
capturer.Wait();
EXPECT_FALSE(child->current_frame_host()->IsSandboxed(
network::mojom::WebSandboxFlags::kAll));
EXPECT_FALSE(
child->current_frame_host()->GetLastCommittedOrigin().opaque());
EXPECT_EQ(child->current_frame_host()->GetLastCommittedOrigin(),
url::Origin::Create(main_url));
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTestNoServer,
HistoryNavigationToPreviouslyNonSandboxedDocument) {
net::test_server::ControllableHttpResponse response1(
embedded_test_server(), "/sandboxed_on_second_load_only");
net::test_server::ControllableHttpResponse response2(
embedded_test_server(), "/sandboxed_on_second_load_only");
ASSERT_TRUE(embedded_test_server()->Start());
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
FrameTreeNode* root =
static_cast<WebContentsImpl*>(contents())->GetPrimaryFrameTree().root();
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/sandboxed_on_second_load_only"));
{
TestNavigationObserver nav_observer(contents());
shell()->LoadURL(main_url);
response1.WaitForRequest();
response1.Send(
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"Cache-Control: no-store\r\n"
"\r\n"
"non-sandboxed document");
response1.Done();
nav_observer.Wait();
EXPECT_EQ(main_url, controller.GetLastCommittedEntry()->GetURL());
EXPECT_FALSE(root->current_frame_host()->IsSandboxed(
network::mojom::WebSandboxFlags::kAll));
EXPECT_FALSE(root->current_frame_host()->GetLastCommittedOrigin().opaque());
EXPECT_EQ(url::Origin::Create(main_url),
root->current_frame_host()->GetLastCommittedOrigin());
}
{
TestNavigationObserver back_load_observer(contents());
GURL url_2(embedded_test_server()->GetURL("b.com", "/title2.html"));
shell()->LoadURL(url_2);
back_load_observer.Wait();
EXPECT_EQ(url_2, controller.GetLastCommittedEntry()->GetURL());
}
{
TestNavigationObserver nav_observer(contents());
controller.GoBack();
response2.WaitForRequest();
response2.Send(
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"Content-Security-Policy: sandbox\r\n"
"\r\n"
"sandboxed document");
response2.Done();
nav_observer.Wait();
EXPECT_EQ(main_url, controller.GetLastCommittedEntry()->GetURL());
EXPECT_TRUE(root->current_frame_host()->IsSandboxed(
network::mojom::WebSandboxFlags::kAll));
EXPECT_TRUE(root->current_frame_host()->GetLastCommittedOrigin().opaque());
EXPECT_TRUE(
root->current_frame_host()->GetLastCommittedOrigin().CanBeDerivedFrom(
main_url));
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
HistoryNavigationToPreviouslyNonSandboxedDocumentOnIframe) {
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
GURL main_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root =
static_cast<WebContentsImpl*>(contents())->GetPrimaryFrameTree().root();
{
LoadCommittedCapturer capturer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root, R"(
let iframe = document.createElement('iframe');
iframe.id = 'child';
iframe.src = location.href;
document.body.appendChild(iframe);)"));
capturer.Wait();
}
FrameTreeNode* child = root->child_at(0);
{
FrameNavigateParamsCapturer capturer(child);
EXPECT_TRUE(ExecJs(root, R"(
document.getElementById('child').src = 'about:blank';)"));
capturer.Wait();
EXPECT_FALSE(child->current_frame_host()->IsSandboxed(
network::mojom::WebSandboxFlags::kAll));
EXPECT_FALSE(
child->current_frame_host()->GetLastCommittedOrigin().opaque());
EXPECT_EQ(child->current_frame_host()->GetLastCommittedOrigin(),
root->current_frame_host()->GetLastCommittedOrigin());
}
{
GURL url_2(embedded_test_server()->GetURL("b.com", "/title2.html"));
FrameNavigateParamsCapturer capturer(child);
NavigateFrameToURL(child, url_2);
capturer.Wait();
}
{
EXPECT_TRUE(ExecJs(
root, "document.getElementById('child').setAttribute('sandbox', '');"));
FrameNavigateParamsCapturer capturer(child);
controller.GoBack();
capturer.Wait();
EXPECT_TRUE(child->current_frame_host()->IsSandboxed(
network::mojom::WebSandboxFlags::kAll));
EXPECT_TRUE(child->current_frame_host()->GetLastCommittedOrigin().opaque());
EXPECT_TRUE(
child->current_frame_host()->GetLastCommittedOrigin().CanBeDerivedFrom(
main_url));
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
DeleteSpeculativeRenderFrameHostDueToNavigationCancellation_MainFrame) {
GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url_a(embedded_test_server()->GetURL("a.com", "/title2.html"));
GURL url_b(embedded_test_server()->GetURL("b.com", "/title3.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
if (ShouldCreateNewHostForAllFrames()) {
SCOPED_TRACE(testing::Message()
<< " Testing main frame same-site navigation.");
TestNavigationManager navigation_manager(contents(), url_a);
EXPECT_TRUE(ExecJs(root, JsReplace("location.href = $1;", url_a)));
EXPECT_TRUE(navigation_manager.WaitForRequestStart());
EXPECT_TRUE(root->render_manager()->speculative_frame_host());
root->ResetNavigationRequest(NavigationDiscardReason::kCancelled);
EXPECT_FALSE(root->render_manager()->speculative_frame_host());
}
if (AreAllSitesIsolatedForTesting() || ShouldCreateNewHostForAllFrames()) {
SCOPED_TRACE(testing::Message()
<< " Testing main frame cross-site navigation.");
TestNavigationManager navigation_manager(contents(), url_b);
EXPECT_TRUE(ExecJs(root, JsReplace("location.href = $1;", url_b)));
EXPECT_TRUE(navigation_manager.WaitForRequestStart());
EXPECT_TRUE(root->render_manager()->speculative_frame_host());
root->ResetNavigationRequest(NavigationDiscardReason::kCancelled);
EXPECT_FALSE(root->render_manager()->speculative_frame_host());
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
DeleteSpeculativeRenderFrameHostDueToNavigationCancellation_Subframe) {
GURL main_url(
embedded_test_server()->GetURL("a.com", "/page_with_iframe.html"));
GURL url_a(embedded_test_server()->GetURL("a.com", "/title2.html"));
GURL url_b(embedded_test_server()->GetURL("b.com", "/title3.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child = root->child_at(0);
if (ShouldCreateNewHostForSameSiteSubframe()) {
SCOPED_TRACE(testing::Message()
<< " Testing subframe same-site navigation.");
TestNavigationManager navigation_manager(contents(), url_a);
EXPECT_TRUE(ExecJs(child, JsReplace("location.href = $1;", url_a)));
EXPECT_TRUE(navigation_manager.WaitForRequestStart());
EXPECT_TRUE(child->render_manager()->speculative_frame_host());
child->ResetNavigationRequest(NavigationDiscardReason::kCancelled);
EXPECT_FALSE(child->render_manager()->speculative_frame_host());
}
if (AreAllSitesIsolatedForTesting() ||
ShouldCreateNewHostForSameSiteSubframe()) {
SCOPED_TRACE(testing::Message()
<< " Testing subframe same-site navigation.");
TestNavigationManager navigation_manager(contents(), url_b);
EXPECT_TRUE(ExecJs(child, JsReplace("location.href = $1;", url_b)));
EXPECT_TRUE(navigation_manager.WaitForRequestStart());
EXPECT_TRUE(child->render_manager()->speculative_frame_host());
child->ResetNavigationRequest(NavigationDiscardReason::kCancelled);
EXPECT_FALSE(child->render_manager()->speculative_frame_host());
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
DeleteSpeculativeRenderFrameHostDueToFrameDeletion_MainFrame) {
GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url_a(embedded_test_server()->GetURL("a.com", "/title2.html"));
GURL url_b(embedded_test_server()->GetURL("b.com", "/title3.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* original_root = contents()->GetPrimaryFrameTree().root();
if (ShouldCreateNewHostForAllFrames()) {
SCOPED_TRACE(testing::Message()
<< " Testing main frame same-site navigation.");
ShellAddedObserver new_shell_observer;
EXPECT_TRUE(ExecJs(original_root,
"var w = window.open('" + main_url.spec() + "');"));
Shell* new_shell = new_shell_observer.GetShell();
ASSERT_NE(new_shell->web_contents(), shell()->web_contents());
EXPECT_TRUE(WaitForLoadStop(new_shell->web_contents()));
FrameTreeNode* new_window_root =
static_cast<WebContentsImpl*>(new_shell->web_contents())
->GetPrimaryFrameTree()
.root();
TestNavigationManager navigation_manager(new_shell->web_contents(), url_a);
EXPECT_TRUE(
ExecJs(new_window_root, JsReplace("location.href = $1;", url_a)));
EXPECT_TRUE(navigation_manager.WaitForRequestStart());
EXPECT_TRUE(new_window_root->render_manager()->speculative_frame_host());
EXPECT_TRUE(ExecJs(original_root, "w.close()"));
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_FALSE(navigation_manager.was_committed());
}
if (AreAllSitesIsolatedForTesting() || ShouldCreateNewHostForAllFrames()) {
SCOPED_TRACE(testing::Message()
<< " Testing main frame cross-site navigation.");
ShellAddedObserver new_shell_observer;
EXPECT_TRUE(ExecJs(original_root,
"var w = window.open('" + main_url.spec() + "');"));
Shell* new_shell = new_shell_observer.GetShell();
ASSERT_NE(new_shell->web_contents(), shell()->web_contents());
EXPECT_TRUE(WaitForLoadStop(new_shell->web_contents()));
FrameTreeNode* new_window_root =
static_cast<WebContentsImpl*>(new_shell->web_contents())
->GetPrimaryFrameTree()
.root();
TestNavigationManager navigation_manager(new_shell->web_contents(), url_b);
EXPECT_TRUE(
ExecJs(new_window_root, JsReplace("location.href = $1;", url_b)));
EXPECT_TRUE(navigation_manager.WaitForRequestStart());
EXPECT_TRUE(new_window_root->render_manager()->speculative_frame_host());
EXPECT_TRUE(ExecJs(original_root, "w.close()"));
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_FALSE(navigation_manager.was_committed());
}
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
DeleteSpeculativeRenderFrameHostDueToFrameDeletion_Subframe) {
GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url_a(embedded_test_server()->GetURL("a.com", "/title2.html"));
GURL url_b(embedded_test_server()->GetURL("b.com", "/title3.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
if (ShouldCreateNewHostForSameSiteSubframe()) {
SCOPED_TRACE(testing::Message()
<< " Testing subframe same-site navigation.");
{
LoadCommittedCapturer capturer(contents());
EXPECT_TRUE(ExecJs(root, JsReplace(kAddFrameWithSrcScript, main_url)));
capturer.Wait();
}
TestNavigationManager navigation_manager(contents(), url_a);
EXPECT_TRUE(
ExecJs(root->child_at(0), JsReplace("location.href = $1;", url_a)));
EXPECT_TRUE(navigation_manager.WaitForRequestStart());
EXPECT_TRUE(root->child_at(0)->render_manager()->speculative_frame_host());
EXPECT_TRUE(
ExecJs(root, "document.getElementsByTagName('iframe')[0].remove()"));
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_FALSE(navigation_manager.was_committed());
}
if (AreAllSitesIsolatedForTesting() ||
ShouldCreateNewHostForSameSiteSubframe()) {
SCOPED_TRACE(testing::Message()
<< " Testing subframe cross-site navigation.");
{
LoadCommittedCapturer capturer(contents());
EXPECT_TRUE(ExecJs(root, JsReplace(kAddFrameWithSrcScript, main_url)));
capturer.Wait();
}
TestNavigationManager navigation_manager(contents(), url_b);
EXPECT_TRUE(
ExecJs(root->child_at(0), JsReplace("location.href = $1;", url_b)));
EXPECT_TRUE(navigation_manager.WaitForRequestStart());
EXPECT_TRUE(root->child_at(0)->render_manager()->speculative_frame_host());
EXPECT_TRUE(
ExecJs(root, "document.getElementsByTagName('iframe')[0].remove()"));
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
EXPECT_FALSE(navigation_manager.was_committed());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
StartNewNavigationWithExistingNavigation_RequestStart) {
if (ShouldCreateNewHostForAllFrames()) {
return;
}
DisableBackForwardCacheForTesting(
contents(), BackForwardCacheImpl::TEST_ASSUMES_NO_RENDER_FRAME_CHANGE);
GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html"));
GURL url_a3(embedded_test_server()->GetURL("a.com", "/title3.html"));
GURL url_b1(embedded_test_server()->GetURL("b.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_a1));
TestNavigationManager a2_navigation(shell()->web_contents(), url_a2);
shell()->LoadURL(url_a2);
EXPECT_TRUE(a2_navigation.WaitForRequestStart());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(root->navigation_request(), a2_navigation.GetNavigationHandle());
TestNavigationManager b1_navigation(shell()->web_contents(), url_b1);
shell()->LoadURL(url_b1);
EXPECT_TRUE(b1_navigation.WaitForRequestStart());
EXPECT_EQ(url_b1, b1_navigation.GetNavigationHandle()->GetURL());
EXPECT_EQ(root->navigation_request(), b1_navigation.GetNavigationHandle());
ASSERT_TRUE(a2_navigation.WaitForNavigationFinished());
EXPECT_FALSE(a2_navigation.was_committed());
TestNavigationManager a3_navigation(shell()->web_contents(), url_a3);
shell()->LoadURL(url_a3);
EXPECT_TRUE(a3_navigation.WaitForRequestStart());
EXPECT_EQ(url_a3, a3_navigation.GetNavigationHandle()->GetURL());
EXPECT_EQ(root->navigation_request(), a3_navigation.GetNavigationHandle());
ASSERT_TRUE(b1_navigation.WaitForNavigationFinished());
EXPECT_FALSE(b1_navigation.was_committed());
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
StartNewNavigationWithExistingNavigation_RequestStart_History) {
if (ShouldCreateNewHostForAllFrames()) {
return;
}
DisableBackForwardCacheForTesting(
contents(), BackForwardCacheImpl::TEST_ASSUMES_NO_RENDER_FRAME_CHANGE);
GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url_b1(embedded_test_server()->GetURL("b.com", "/title1.html"));
GURL url_b2(embedded_test_server()->GetURL("b.com", "/title2.html"));
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_TRUE(NavigateToURL(shell(), url_a1));
NavigationEntryImpl* entry_a1 = controller.GetLastCommittedEntry();
SiteInstance* site_instance_a1 =
root->current_frame_host()->GetSiteInstance();
EXPECT_EQ(site_instance_a1, entry_a1->site_instance());
EXPECT_TRUE(NavigateToURL(shell(), url_b1));
NavigationEntryImpl* entry_b1 = controller.GetLastCommittedEntry();
SiteInstance* site_instance_b1 =
root->current_frame_host()->GetSiteInstance();
EXPECT_EQ(site_instance_b1, entry_b1->site_instance());
EXPECT_TRUE(NavigateToURL(shell(), url_b2));
NavigationEntryImpl* entry_b2 = controller.GetLastCommittedEntry();
SiteInstance* site_instance_b2 =
root->current_frame_host()->GetSiteInstance();
EXPECT_EQ(site_instance_b2, entry_b2->site_instance());
TestNavigationManager b1_navigation(shell()->web_contents(), url_b1);
controller.GoBack();
EXPECT_TRUE(b1_navigation.WaitForRequestStart());
EXPECT_EQ(root->navigation_request(), b1_navigation.GetNavigationHandle());
TestNavigationManager a1_navigation(shell()->web_contents(), url_a1);
controller.GoBack();
EXPECT_TRUE(a1_navigation.WaitForRequestStart());
EXPECT_EQ(url_a1, a1_navigation.GetNavigationHandle()->GetURL());
EXPECT_EQ(root->navigation_request(), a1_navigation.GetNavigationHandle());
ASSERT_TRUE(b1_navigation.WaitForNavigationFinished());
EXPECT_FALSE(b1_navigation.was_committed());
ASSERT_TRUE(a1_navigation.WaitForNavigationFinished());
EXPECT_TRUE(a1_navigation.was_successful());
EXPECT_EQ(entry_a1, controller.GetLastCommittedEntry());
EXPECT_EQ(site_instance_a1, entry_a1->site_instance());
EXPECT_EQ(site_instance_b1, entry_b1->site_instance());
EXPECT_EQ(site_instance_b2, entry_b2->site_instance());
}
namespace {
void StartNavigationOnReadyToCommit(
Shell* shell,
TestNavigationManager& prev_navigation_manager,
GURL& new_navigation_url) {
base::RunLoop run_loop;
static_cast<NavigationRequest*>(prev_navigation_manager.GetNavigationHandle())
->set_ready_to_commit_callback_for_testing(run_loop.QuitClosure());
prev_navigation_manager.ResumeNavigation();
run_loop.Run();
shell->LoadURL(new_navigation_url);
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
StartNewNavigationWithExistingNavigation_ReadyToCommit) {
if (ShouldCreateNewHostForAllFrames()) {
return;
}
DisableBackForwardCacheForTesting(
contents(), BackForwardCacheImpl::TEST_ASSUMES_NO_RENDER_FRAME_CHANGE);
GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html"));
GURL url_a3(embedded_test_server()->GetURL("a.com", "/title3.html"));
GURL url_b1(embedded_test_server()->GetURL("b.com", "/title1.html"));
GURL url_b2(embedded_test_server()->GetURL("b.com", "/title2.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_a1));
TestNavigationManager a2_navigation(shell()->web_contents(), url_a2);
shell()->LoadURL(url_a2);
EXPECT_TRUE(a2_navigation.WaitForResponse());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(root->navigation_request(), a2_navigation.GetNavigationHandle());
TestNavigationManager b1_navigation(shell()->web_contents(), url_b1);
StartNavigationOnReadyToCommit(shell(), a2_navigation, url_b1);
EXPECT_TRUE(b1_navigation.WaitForRequestStart());
EXPECT_EQ(url_b1, b1_navigation.GetNavigationHandle()->GetURL());
EXPECT_EQ(root->navigation_request(), b1_navigation.GetNavigationHandle());
ASSERT_TRUE(a2_navigation.WaitForNavigationFinished());
EXPECT_TRUE(a2_navigation.was_successful());
EXPECT_TRUE(b1_navigation.GetNavigationHandle());
TestNavigationManager a3_navigation(shell()->web_contents(), url_a3);
EXPECT_TRUE(b1_navigation.WaitForResponse());
StartNavigationOnReadyToCommit(shell(), b1_navigation, url_a3);
if (ShouldAvoidRedundantNavigationCancellations()) {
ASSERT_TRUE(b1_navigation.WaitForNavigationFinished());
EXPECT_TRUE(b1_navigation.was_successful());
EXPECT_TRUE(a3_navigation.WaitForResponse());
EXPECT_TRUE(a3_navigation.GetNavigationHandle());
ASSERT_TRUE(a3_navigation.WaitForNavigationFinished());
EXPECT_TRUE(a3_navigation.was_successful());
} else {
EXPECT_TRUE(a3_navigation.WaitForResponse());
EXPECT_EQ(url_a3, a3_navigation.GetNavigationHandle()->GetURL());
EXPECT_EQ(root->navigation_request(), a3_navigation.GetNavigationHandle());
EXPECT_TRUE(b1_navigation.WaitForNavigationFinished());
EXPECT_FALSE(b1_navigation.was_committed());
TestNavigationManager b2_navigation(shell()->web_contents(), url_b2);
DidCommitNavigationCanceller ignore_a3_commit(
shell()->web_contents(), url_a3,
base::BindLambdaForTesting([&]() { shell()->LoadURL(url_b2); }));
a3_navigation.ResumeNavigation();
EXPECT_TRUE(b2_navigation.WaitForResponse());
EXPECT_TRUE(a3_navigation.GetNavigationHandle());
EXPECT_TRUE(b2_navigation.WaitForNavigationFinished());
EXPECT_TRUE(b2_navigation.was_successful());
EXPECT_TRUE(a3_navigation.WaitForNavigationFinished());
EXPECT_FALSE(a3_navigation.was_committed());
}
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
ResetNavigationRequestWontDeletePendingCommitRFH) {
GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url_b1(embedded_test_server()->GetURL("b.com", "/title1.html"));
GURL url_b2(embedded_test_server()->GetURL("b.com", "/title2.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
RenderFrameHostImplWrapper rfh_a(current_main_frame_host());
TestNavigationManager b1_nav(shell()->web_contents(), url_b1);
TestNavigationManager b2_nav(shell()->web_contents(), url_b2);
DidCommitNavigationCanceller ignore_b1_commit(
shell()->web_contents(), url_b1,
base::BindLambdaForTesting([&]() { shell()->LoadURL(url_b2); }));
shell()->LoadURL(url_b1);
EXPECT_TRUE(b1_nav.WaitForResponse());
EXPECT_EQ(b1_nav.GetNavigationHandle(), root->navigation_request());
b1_nav.ResumeNavigation();
EXPECT_TRUE(b2_nav.WaitForRequestStart());
EXPECT_EQ(b2_nav.GetNavigationHandle(), root->navigation_request());
EXPECT_TRUE(b1_nav.GetNavigationHandle());
root->ResetNavigationRequest(NavigationDiscardReason::kCancelled);
ASSERT_TRUE(b2_nav.WaitForNavigationFinished());
EXPECT_FALSE(b2_nav.was_committed());
EXPECT_FALSE(b2_nav.GetNavigationHandle());
EXPECT_TRUE(b1_nav.GetNavigationHandle());
EXPECT_TRUE(root->render_manager()->speculative_frame_host());
EXPECT_EQ(b1_nav.GetNavigationHandle()->GetRenderFrameHost(),
root->render_manager()->speculative_frame_host());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
UnloadingPreviousRFHOnCommitWontCancelNavigation) {
if (!ShouldAvoidRedundantNavigationCancellations()) {
return;
}
GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url_b1(embedded_test_server()->GetURL("b.com", "/title1.html"));
GURL url_b2(embedded_test_server()->GetURL("b.com", "/title2.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
RenderFrameHostImplWrapper rfh_a(current_main_frame_host());
TestNavigationManager b1_nav(shell()->web_contents(), url_b1);
TestNavigationManager b2_nav(shell()->web_contents(), url_b2);
NavigationStarterBeforeDidCommitNavigation urlb2_navigation_starter(
contents(), shell(), url_b1, url_b2);
shell()->LoadURL(url_b1);
EXPECT_TRUE(b1_nav.WaitForResponse());
EXPECT_EQ(b1_nav.GetNavigationHandle(), root->navigation_request());
b1_nav.ResumeNavigation();
EXPECT_TRUE(b2_nav.WaitForRequestStart());
EXPECT_EQ(b2_nav.GetNavigationHandle(), root->navigation_request());
ASSERT_TRUE(b1_nav.WaitForNavigationFinished());
EXPECT_TRUE(b1_nav.was_successful());
RenderFrameHostImplWrapper rfh_b(current_main_frame_host());
EXPECT_NE(rfh_b.get(), rfh_a.get());
EXPECT_TRUE(!rfh_a.get() || !rfh_a->IsActive());
EXPECT_NE(nullptr, root->navigation_request());
EXPECT_EQ(b2_nav.GetNavigationHandle(), root->navigation_request());
EXPECT_EQ(root->navigation_request()->GetAssociatedRFHType(),
NavigationRequest::AssociatedRenderFrameHostType::NONE);
b2_nav.ResumeNavigation();
EXPECT_TRUE(b2_nav.WaitForResponse());
if (IsBackForwardCacheEnabled() || ShouldCreateNewHostForAllFrames()) {
EXPECT_EQ(root->navigation_request()->GetAssociatedRFHType(),
NavigationRequest::AssociatedRenderFrameHostType::SPECULATIVE);
} else {
EXPECT_EQ(root->navigation_request()->GetAssociatedRFHType(),
NavigationRequest::AssociatedRenderFrameHostType::CURRENT);
}
ASSERT_TRUE(b2_nav.WaitForNavigationFinished());
EXPECT_TRUE(b2_nav.was_successful());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
BFCacheRestoreDeferredWhenPendingCommitRFHExists) {
if (!ShouldAvoidRedundantNavigationCancellations() ||
!IsBackForwardCacheEnabled()) {
return;
}
GURL url_1(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url_2(embedded_test_server()->GetURL("b.com", "/title2.html"));
GURL url_3(embedded_test_server()->GetURL("c.com", "/title3.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_1));
EXPECT_TRUE(NavigateToURL(shell(), url_2));
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
TestNavigationManager pending_commit_nav_manager(contents(), url_3);
TestActivationManager bfcache_nav_manager(contents(), url_1);
{
DidCommitNavigationCanceller ignore_url_3_commit(
contents(), url_3,
base::BindLambdaForTesting([&]() { controller.GoBack(); }));
shell()->LoadURL(url_3);
EXPECT_TRUE(pending_commit_nav_manager.WaitForResponse());
RenderFrameHostImplWrapper spec_rfh(
root->render_manager()->speculative_frame_host());
EXPECT_TRUE(spec_rfh.get());
pending_commit_nav_manager.ResumeNavigation();
EXPECT_TRUE(bfcache_nav_manager.WaitForBeforeChecks());
EXPECT_EQ(spec_rfh.get(), root->render_manager()->speculative_frame_host());
EXPECT_TRUE(spec_rfh->HasPendingCommitForCrossDocumentNavigation());
}
bfcache_nav_manager.ResumeActivation();
NavigationRequest* bfcache_nav = static_cast<NavigationRequest*>(
bfcache_nav_manager.GetNavigationHandle());
EXPECT_TRUE(bfcache_nav->IsQueued());
GURL url_2_foo(embedded_test_server()->GetURL("b.com", "/title2.html#foo"));
EXPECT_TRUE(ExecJs(contents(), "location.href = '#foo'"));
EXPECT_EQ(url_2_foo, contents()->GetLastCommittedURL());
EXPECT_TRUE(bfcache_nav->IsQueued());
root->render_manager()->DiscardSpeculativeRenderFrameHostForShutdown();
EXPECT_TRUE(pending_commit_nav_manager.WaitForNavigationFinished());
EXPECT_FALSE(pending_commit_nav_manager.was_committed());
bfcache_nav_manager.WaitForNavigationFinished();
EXPECT_TRUE(bfcache_nav_manager.was_successful());
EXPECT_EQ(url_1, contents()->GetLastCommittedURL());
}
IN_PROC_BROWSER_TEST_P(
NavigationControllerBrowserTest,
BFCacheRestoreDeferredAndEvictedWhenPendingCommitRFHExists) {
if (!ShouldAvoidRedundantNavigationCancellations() ||
!IsBackForwardCacheEnabled()) {
return;
}
GURL url_1(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url_2(embedded_test_server()->GetURL("b.com", "/title2.html"));
GURL url_3(embedded_test_server()->GetURL("c.com", "/title3.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_1));
NavigationControllerImpl& controller =
static_cast<NavigationControllerImpl&>(contents()->GetController());
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
RenderFrameHostImplWrapper url_1_rfh(root->current_frame_host());
EXPECT_TRUE(NavigateToURL(shell(), url_2));
EXPECT_TRUE(url_1_rfh->IsInBackForwardCache());
TestNavigationManager pending_commit_nav_manager(contents(), url_3);
TestActivationManager bfcache_nav_manager(contents(), url_1);
{
DidCommitNavigationCanceller ignore_url_3_commit(
contents(), url_3,
base::BindLambdaForTesting([&]() { controller.GoBack(); }));
shell()->LoadURL(url_3);
EXPECT_TRUE(pending_commit_nav_manager.WaitForResponse());
RenderFrameHostImplWrapper spec_rfh(
root->render_manager()->speculative_frame_host());
EXPECT_TRUE(spec_rfh.get());
pending_commit_nav_manager.ResumeNavigation();
EXPECT_TRUE(bfcache_nav_manager.WaitForBeforeChecks());
EXPECT_EQ(spec_rfh.get(), root->render_manager()->speculative_frame_host());
EXPECT_TRUE(spec_rfh->HasPendingCommitForCrossDocumentNavigation());
}
bfcache_nav_manager.ResumeActivation();
NavigationRequest* bfcache_nav = static_cast<NavigationRequest*>(
bfcache_nav_manager.GetNavigationHandle());
EXPECT_TRUE(bfcache_nav->IsQueued());
DisableBFCacheForRFHForTesting(url_1_rfh.get());
TestNavigationManager new_history_navigation_manager(contents(), url_1);
root->render_manager()->DiscardSpeculativeRenderFrameHostForShutdown();
EXPECT_TRUE(pending_commit_nav_manager.WaitForNavigationFinished());
EXPECT_FALSE(pending_commit_nav_manager.was_committed());
EXPECT_TRUE(bfcache_nav->IsQueued());
bfcache_nav_manager.WaitForNavigationFinished();
EXPECT_FALSE(bfcache_nav_manager.was_committed());
EXPECT_TRUE(new_history_navigation_manager.WaitForResponse());
EXPECT_TRUE(new_history_navigation_manager.WaitForNavigationFinished());
EXPECT_TRUE(new_history_navigation_manager.was_successful());
EXPECT_EQ(url_1, contents()->GetLastCommittedURL());
}
IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
WebUICreatedForQueuedNavigation) {
GURL url_1(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL url_2(embedded_test_server()->GetURL("b.com", "/title2.html"));
GURL url_webui(std::string(kChromeUIScheme) + "://" +
std::string(kChromeUIGpuHost));
EXPECT_TRUE(NavigateToURL(shell(), url_1));
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
TestNavigationManager pending_commit_nav_manager(contents(), url_2);
TestNavigationManager webui_nav_manager(contents(), url_webui);
WebUIImpl* created_webui = nullptr;
{
DidCommitNavigationCanceller ignore_url_2_commit(
contents(), url_2,
base::BindLambdaForTesting([&]() { shell()->LoadURL(url_webui); }));
shell()->LoadURL(url_2);
EXPECT_TRUE(pending_commit_nav_manager.WaitForResponse());
RenderFrameHostImplWrapper spec_rfh(
root->render_manager()->speculative_frame_host());
EXPECT_TRUE(spec_rfh.get());
pending_commit_nav_manager.ResumeNavigation();
EXPECT_TRUE(webui_nav_manager.WaitForRequestStart());
NavigationRequest* webui_nav = static_cast<NavigationRequest*>(
webui_nav_manager.GetNavigationHandle());
EXPECT_FALSE(webui_nav->HasRenderFrameHost());
EXPECT_TRUE(webui_nav->HasWebUI());
created_webui = webui_nav->web_ui();
EXPECT_FALSE(created_webui->HasRenderFrameHost());
EXPECT_EQ(spec_rfh.get(), root->render_manager()->speculative_frame_host());
EXPECT_TRUE(spec_rfh->HasPendingCommitForCrossDocumentNavigation());
EXPECT_NE(webui_nav->dest_site_instance(), spec_rfh->GetSiteInstance());
EXPECT_FALSE(spec_rfh->web_ui());
}
root->render_manager()->DiscardSpeculativeRenderFrameHostForShutdown();
EXPECT_TRUE(pending_commit_nav_manager.WaitForNavigationFinished());
EXPECT_FALSE(pending_commit_nav_manager.was_committed());
webui_nav_manager.ResumeNavigation();
EXPECT_TRUE(webui_nav_manager.WaitForResponse());
NavigationRequest* webui_nav =
static_cast<NavigationRequest*>(webui_nav_manager.GetNavigationHandle());
EXPECT_TRUE(webui_nav->HasRenderFrameHost());
EXPECT_FALSE(webui_nav->HasWebUI());
EXPECT_EQ(created_webui, webui_nav->GetRenderFrameHost()->web_ui());
EXPECT_TRUE(created_webui->HasRenderFrameHost());
EXPECT_EQ(created_webui->GetRenderFrameHost(),
webui_nav->GetRenderFrameHost());
EXPECT_EQ(webui_nav->GetRenderFrameHost(),
root->render_manager()->speculative_frame_host());
webui_nav_manager.ResumeNavigation();
EXPECT_TRUE(webui_nav_manager.WaitForNavigationFinished());
EXPECT_TRUE(webui_nav_manager.was_successful());
EXPECT_EQ(url_webui, contents()->GetLastCommittedURL());
EXPECT_EQ(created_webui, current_main_frame_host()->web_ui());
EXPECT_EQ(created_webui->GetRenderFrameHost(), current_main_frame_host());
}
INSTANTIATE_TEST_SUITE_P(
All,
NavigationControllerAlertDialogBrowserTest,
testing::Combine(testing::ValuesIn(RenderDocumentFeatureLevelValues()),
testing::Bool()),
NavigationControllerBrowserTest::DescribeParams);
INSTANTIATE_TEST_SUITE_P(
All,
NavigationControllerBrowserTest,
testing::Combine(testing::ValuesIn(RenderDocumentFeatureLevelValues()),
testing::Bool()),
NavigationControllerBrowserTest::DescribeParams);
INSTANTIATE_TEST_SUITE_P(
All,
NavigationControllerBrowserTestNoServer,
testing::Combine(testing::ValuesIn(RenderDocumentFeatureLevelValues()),
testing::Bool()),
NavigationControllerBrowserTest::DescribeParams);
INSTANTIATE_TEST_SUITE_P(
All,
NavigationControllerMainDocumentSequenceNumberBrowserTest,
testing::Combine(testing::ValuesIn(RenderDocumentFeatureLevelValues()),
testing::Bool()),
NavigationControllerBrowserTest::DescribeParams);
INSTANTIATE_TEST_SUITE_P(
All,
RequestMonitoringNavigationBrowserTest,
testing::Combine(testing::ValuesIn(RenderDocumentFeatureLevelValues()),
testing::Bool()),
NavigationControllerBrowserTest::DescribeParams);
INSTANTIATE_TEST_SUITE_P(
All,
SandboxedNavigationControllerBrowserTest,
testing::Combine(testing::ValuesIn(RenderDocumentFeatureLevelValues()),
testing::Bool()),
NavigationControllerBrowserTest::DescribeParams);
INSTANTIATE_TEST_SUITE_P(
All,
SandboxedNavigationControllerWithBfcacheBrowserTest,
testing::Combine(testing::ValuesIn(RenderDocumentFeatureLevelValues()),
testing::Values(true)),
NavigationControllerBrowserTest::DescribeParams);
INSTANTIATE_TEST_SUITE_P(
All,
SandboxedNavigationControllerPopupBrowserTest,
testing::Combine(testing::ValuesIn(RenderDocumentFeatureLevelValues()),
testing::Bool()),
NavigationControllerBrowserTest::DescribeParams);
INSTANTIATE_TEST_SUITE_P(
All,
InitialEmptyDocNavigationControllerBrowserTest,
testing::Combine(testing::ValuesIn(RenderDocumentFeatureLevelValues()),
testing::Bool()),
InitialEmptyDocNavigationControllerBrowserTest::DescribeParams);
INSTANTIATE_TEST_SUITE_P(
All,
LoadDataWithBaseURLWithPossiblyEmptyURLsBrowserTest,
testing::Combine(testing::ValuesIn(RenderDocumentFeatureLevelValues()),
testing::Bool(),
testing::Bool(),
testing::Bool()),
LoadDataWithBaseURLWithPossiblyEmptyURLsBrowserTest::DescribeParams);
INSTANTIATE_TEST_SUITE_P(
All,
LoadDataWithBaseURLBrowserTest,
testing::Combine(testing::ValuesIn(RenderDocumentFeatureLevelValues()),
testing::Bool()),
LoadDataWithBaseURLBrowserTest::DescribeParams);
}