#include "content/browser/site_per_process_browsertest.h"
#include <stddef.h>
#include <stdint.h>
#include <algorithm>
#include <cmath>
#include <list>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/cxx17_backports.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/json/json_reader.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/memory/scoped_refptr.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/scoped_observation.h"
#include "base/strings/pattern.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/test_timeouts.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "cc/base/math_util.h"
#include "cc/input/touch_action.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/process_lock.h"
#include "content/browser/renderer_host/agent_scheduling_group_host.h"
#include "content/browser/renderer_host/cross_process_frame_connector.h"
#include "content/browser/renderer_host/frame_navigation_entry.h"
#include "content/browser/renderer_host/frame_tree.h"
#include "content/browser/renderer_host/input/input_router.h"
#include "content/browser/renderer_host/input/synthetic_gesture.h"
#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
#include "content/browser/renderer_host/input/synthetic_tap_gesture.h"
#include "content/browser/renderer_host/input/synthetic_touchscreen_pinch_gesture.h"
#include "content/browser/renderer_host/navigation_controller_impl.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/navigator.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/renderer_host/render_frame_proxy_host.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
#include "content/browser/renderer_host/render_widget_host_view_child_frame.h"
#include "content/browser/site_info.h"
#include "content/browser/storage_partition_impl.h"
#include "content/browser/url_loader_factory_getter.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/content_navigation_policy.h"
#include "content/common/frame.mojom-test-utils.h"
#include "content/common/input/actions_parser.h"
#include "content/common/input/synthetic_pinch_gesture_params.h"
#include "content/common/renderer.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/context_menu_params.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/javascript_dialog_manager.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_process_host_priority_client.h"
#include "content/public/browser/site_isolation_policy.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.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_content_browser_client.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/content_mock_cert_verifier.h"
#include "content/public/test/fenced_frame_test_util.h"
#include "content/public/test/hit_test_region_observer.h"
#include "content/public/test/navigation_handle_observer.h"
#include "content/public/test/policy_container_utils.h"
#include "content/public/test/render_frame_host_test_support.h"
#include "content/public/test/test_frame_navigation_observer.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_navigation_throttle.h"
#include "content/public/test/test_navigation_throttle_inserter.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/common/main_frame_counter_test_impl.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 "ipc/constants.mojom.h"
#include "ipc/ipc_security_test_util.h"
#include "media/base/media_switches.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/test_support/test_utils.h"
#include "net/dns/mock_host_resolver.h"
#include "net/http/mock_http_cache.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/web_sandbox_flags.h"
#include "services/network/public/mojom/web_sandbox_flags.mojom-shared.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/public/common/permissions_policy/origin_with_possible_wildcards.h"
#include "third_party/blink/public/common/permissions_policy/permissions_policy.h"
#include "third_party/blink/public/common/permissions_policy/policy_value.h"
#include "third_party/blink/public/common/switches.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/mojom/frame/frame.mojom-test-utils.h"
#include "third_party/blink/public/mojom/frame/frame.mojom.h"
#include "third_party/blink/public/mojom/frame/frame_replication_state.mojom.h"
#include "third_party/blink/public/mojom/leak_detector/leak_detector.mojom-test-utils.h"
#include "third_party/blink/public/mojom/leak_detector/leak_detector.mojom.h"
#include "third_party/blink/public/mojom/page/widget.mojom-test-utils.h"
#include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom.h"
#include "ui/display/display_switches.h"
#include "ui/display/screen.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/blink/blink_features.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/dom_key.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/transform.h"
#include "ui/latency/latency_info.h"
#include "ui/native_theme/native_theme_features.h"
#if defined(USE_AURA)
#include "content/browser/renderer_host/render_widget_host_view_aura.h"
#include "ui/aura/window.h"
#endif
#if BUILDFLAG(IS_ANDROID)
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "content/browser/android/gesture_listener_manager.h"
#include "content/browser/android/ime_adapter_android.h"
#include "content/browser/renderer_host/input/touch_selection_controller_client_manager_android.h"
#include "content/browser/renderer_host/render_widget_host_view_android.h"
#include "content/browser/web_contents/web_contents_view_android.h"
#include "content/public/browser/android/child_process_importance.h"
#include "content/test/mock_overscroll_refresh_handler_android.h"
#include "ui/android/view_android.h"
#include "ui/android/window_android.h"
#include "ui/events/android/event_handler_android.h"
#include "ui/events/android/motion_event_android.h"
#include "ui/gfx/geometry/point_f.h"
#endif
using ::testing::SizeIs;
using ::testing::WhenSorted;
using ::testing::ElementsAre;
namespace content {
namespace {
void VerifyChildProcessHasMainFrame(
mojo::Remote<mojom::MainFrameCounterTest>& main_frame_counter,
bool expected_state) {
main_frame_counter.FlushForTesting();
base::RunLoop run_loop;
main_frame_counter->HasMainFrame(base::BindOnce(
[](base::RunLoop* loop, bool expected_state, bool has_main_frame) {
EXPECT_EQ(expected_state, has_main_frame);
loop->Quit();
},
&run_loop, expected_state));
run_loop.Run();
}
using CrashVisibility = CrossProcessFrameConnector::CrashVisibility;
void PostMessageAndWaitForReply(FrameTreeNode* sender_ftn,
const std::string& post_message_script,
const std::string& reply_status) {
DOMMessageQueue msg_queue(sender_ftn->current_frame_host());
EXPECT_EQ(true, EvalJs(sender_ftn, "(" + post_message_script + ");"));
std::string status;
while (msg_queue.WaitForMessage(&status)) {
if (status == reply_status)
break;
}
}
int GetReceivedMessages(FrameTreeNode* ftn) {
return EvalJs(ftn, "window.receivedMessages;").ExtractInt();
}
void NavigateNamedFrame(const ToRenderFrameHost& caller_frame,
const GURL& url,
const std::string& name) {
EXPECT_EQ(true, EvalJs(caller_frame,
JsReplace("!!window.open($1, $2)", url, name)));
}
void SimulateMouseClick(RenderWidgetHost* rwh, int x, int y) {
blink::WebMouseEvent mouse_event(
blink::WebInputEvent::Type::kMouseDown,
blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests());
mouse_event.button = blink::WebPointerProperties::Button::kLeft;
mouse_event.SetPositionInWidget(x, y);
rwh->ForwardMouseEvent(mouse_event);
}
EvalJsResult GetOriginFromRenderer(FrameTreeNode* ftn) {
return EvalJs(ftn, "self.origin;");
}
class UserInteractionObserver : public WebContentsObserver {
public:
explicit UserInteractionObserver(WebContents* web_contents)
: WebContentsObserver(web_contents), user_interaction_received_(false) {}
UserInteractionObserver(const UserInteractionObserver&) = delete;
UserInteractionObserver& operator=(const UserInteractionObserver&) = delete;
~UserInteractionObserver() override {}
bool WasUserInteractionReceived() { return user_interaction_received_; }
void Reset() { user_interaction_received_ = false; }
private:
void DidGetUserInteraction(const blink::WebInputEvent& event) override {
user_interaction_received_ = true;
}
bool user_interaction_received_;
};
class VisibleSecurityStateObserver : public WebContentsObserver {
public:
using ConditionCallback = base::RepeatingCallback<bool(WebContents*)>;
VisibleSecurityStateObserver(WebContents* web_contents,
ConditionCallback condition_callback)
: WebContentsObserver(web_contents),
condition_callback_(condition_callback) {}
~VisibleSecurityStateObserver() override = default;
VisibleSecurityStateObserver(const VisibleSecurityStateObserver& other) =
delete;
VisibleSecurityStateObserver& operator=(
const VisibleSecurityStateObserver& other) = delete;
void Wait() {
if (condition_callback_.Run(web_contents()))
return;
run_loop_.Run();
}
void DidChangeVisibleSecurityState() override {
if (condition_callback_.Run(web_contents()))
run_loop_.Quit();
}
private:
ConditionCallback condition_callback_;
base::RunLoop run_loop_;
};
void FocusFrame(FrameTreeNode* frame) {
FrameFocusedObserver focus_observer(frame->current_frame_host());
SimulateMouseClick(frame->current_frame_host()->GetRenderWidgetHost(), 1, 1);
focus_observer.Wait();
}
bool ConvertJSONToPoint(const std::string& str, gfx::PointF* point) {
absl::optional<base::Value> value = base::JSONReader::Read(str);
if (!value.has_value())
return false;
if (!value->is_dict())
return false;
absl::optional<double> x = value->GetDict().FindDouble("x");
absl::optional<double> y = value->GetDict().FindDouble("y");
if (!x.has_value())
return false;
if (!y.has_value())
return false;
point->set_x(x.value());
point->set_y(y.value());
return true;
}
blink::ParsedPermissionsPolicyDeclaration
CreateParsedPermissionsPolicyDeclaration(
blink::mojom::PermissionsPolicyFeature feature,
const std::vector<GURL>& origins,
bool match_all_origins = false,
const absl::optional<GURL> self_if_matches = absl::nullopt) {
blink::ParsedPermissionsPolicyDeclaration declaration;
declaration.feature = feature;
if (self_if_matches.has_value()) {
declaration.self_if_matches = url::Origin::Create(*self_if_matches);
}
declaration.matches_all_origins = match_all_origins;
declaration.matches_opaque_src = match_all_origins;
for (const auto& origin : origins)
declaration.allowed_origins.emplace_back(url::Origin::Create(origin),
false);
std::sort(declaration.allowed_origins.begin(),
declaration.allowed_origins.end());
return declaration;
}
blink::ParsedPermissionsPolicy CreateParsedPermissionsPolicy(
const std::vector<blink::mojom::PermissionsPolicyFeature>& features,
const std::vector<GURL>& origins,
bool match_all_origins = false,
const absl::optional<GURL> self_if_matches = absl::nullopt) {
blink::ParsedPermissionsPolicy result;
result.reserve(features.size());
for (const auto& feature : features)
result.push_back(CreateParsedPermissionsPolicyDeclaration(
feature, origins, match_all_origins, self_if_matches));
return result;
}
blink::ParsedPermissionsPolicy CreateParsedPermissionsPolicyMatchesSelf(
const std::vector<blink::mojom::PermissionsPolicyFeature>& features,
const GURL& self_if_matches) {
return CreateParsedPermissionsPolicy(features, {}, false, self_if_matches);
}
blink::ParsedPermissionsPolicy CreateParsedPermissionsPolicyMatchesAll(
const std::vector<blink::mojom::PermissionsPolicyFeature>& features) {
return CreateParsedPermissionsPolicy(features, {}, true);
}
blink::ParsedPermissionsPolicy CreateParsedPermissionsPolicyMatchesNone(
const std::vector<blink::mojom::PermissionsPolicyFeature>& features) {
return CreateParsedPermissionsPolicy(features, {});
}
void CheckFrameDepth(unsigned int expected_depth, FrameTreeNode* node) {
EXPECT_EQ(expected_depth, node->current_frame_host()->GetFrameDepth());
RenderProcessHostPriorityClient::Priority priority =
node->current_frame_host()->GetRenderWidgetHost()->GetPriority();
EXPECT_EQ(expected_depth, priority.frame_depth);
EXPECT_EQ(expected_depth,
node->current_frame_host()->GetProcess()->GetFrameDepth());
}
void GenerateTapDownGesture(RenderWidgetHost* rwh) {
blink::WebGestureEvent gesture_tap_down(
blink::WebGestureEvent::Type::kGestureTapDown,
blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests(),
blink::WebGestureDevice::kTouchscreen);
gesture_tap_down.is_source_touch_event_set_blocking = true;
rwh->ForwardGestureEvent(gesture_tap_down);
}
}
SitePerProcessBrowserTestBase::SitePerProcessBrowserTestBase() {
#if !BUILDFLAG(IS_ANDROID)
feature_list_.InitAndDisableFeature(features::kOverlayScrollbar);
#endif
}
std::string SitePerProcessBrowserTestBase::DepictFrameTree(
FrameTreeNode* node) {
return visualizer_.DepictFrameTree(node);
}
std::string SitePerProcessBrowserTestBase::WaitForMessageScript(
const std::string& result_expression) {
return base::StringPrintf(
"var onMessagePromise = new Promise(resolve => {"
" window.addEventListener('message', function(event) {"
" resolve(%s);"
" });"
"});",
result_expression.c_str());
}
void SitePerProcessBrowserTestBase::SetUpCommandLine(
base::CommandLine* command_line) {
ContentBrowserTest::SetUpCommandLine(command_line);
IsolateAllSitesForTesting(command_line);
command_line->AppendSwitch(switches::kValidateInputEventStream);
}
void SitePerProcessBrowserTestBase::SetUpOnMainThread() {
host_resolver()->AddRule("*", "127.0.0.1");
SetupCrossSiteRedirector(embedded_test_server());
ASSERT_TRUE(embedded_test_server()->Start());
}
void SitePerProcessBrowserTestBase::ForceUpdateViewportIntersection(
FrameTreeNode* frame_tree_node,
const blink::mojom::ViewportIntersectionState& intersection_state) {
frame_tree_node->render_manager()
->GetProxyToParent()
->cross_process_frame_connector()
->UpdateViewportIntersectionInternal(intersection_state, false);
}
void SitePerProcessBrowserTestBase::RunPostedTasks() {
base::RunLoop loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, loop.QuitClosure());
loop.Run();
}
SitePerProcessBrowserTest::SitePerProcessBrowserTest() {
InitAndEnableRenderDocumentFeature(&feature_list_, GetParam());
}
std::string SitePerProcessBrowserTest::GetExpectedOrigin(
const std::string& host) {
GURL url = embedded_test_server()->GetURL(host, "/");
return url::Origin::Create(url).Serialize();
}
void SitePerProcessIgnoreCertErrorsBrowserTest::SetUpOnMainThread() {
SitePerProcessBrowserTest::SetUpOnMainThread();
mock_cert_verifier_.mock_cert_verifier()->set_default_result(net::OK);
}
void SitePerProcessIgnoreCertErrorsBrowserTest::SetUpCommandLine(
base::CommandLine* command_line) {
SitePerProcessBrowserTest::SetUpCommandLine(command_line);
mock_cert_verifier_.SetUpCommandLine(command_line);
}
void SitePerProcessIgnoreCertErrorsBrowserTest::
SetUpInProcessBrowserTestFixture() {
SitePerProcessBrowserTest::SetUpInProcessBrowserTestFixture();
mock_cert_verifier_.SetUpInProcessBrowserTestFixture();
}
void SitePerProcessIgnoreCertErrorsBrowserTest::
TearDownInProcessBrowserTestFixture() {
SitePerProcessBrowserTest::TearDownInProcessBrowserTestFixture();
mock_cert_verifier_.TearDownInProcessBrowserTestFixture();
}
class SitePerProcessAutoplayBrowserTest : public SitePerProcessBrowserTest {
public:
SitePerProcessAutoplayBrowserTest() = default;
void SetUpCommandLine(base::CommandLine* command_line) override {
SitePerProcessBrowserTestBase::SetUpCommandLine(command_line);
command_line->AppendSwitchASCII(
switches::kAutoplayPolicy,
switches::autoplay::kDocumentUserActivationRequiredPolicy);
}
bool AutoplayAllowed(const ToRenderFrameHost& adapter,
bool with_user_gesture) {
return EvalJs(adapter, "attemptPlay();",
with_user_gesture ? EXECUTE_SCRIPT_DEFAULT_OPTIONS
: EXECUTE_SCRIPT_NO_USER_GESTURE)
.ExtractBool();
}
};
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, CrossSiteIframe) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
TestNavigationObserver observer(shell()->web_contents());
FrameTreeNode* child = root->child_at(0);
GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(child, http_url));
EXPECT_EQ(http_url, observer.last_navigation_url());
EXPECT_TRUE(observer.last_navigation_succeeded());
{
std::set<RenderWidgetHostViewBase*> views_set =
web_contents()->GetRenderWidgetHostViewsInWebContentsTree();
EXPECT_EQ(1U, views_set.size());
}
EXPECT_EQ(
" Site A\n"
" |--Site A\n"
" +--Site A\n"
" |--Site A\n"
" +--Site A\n"
" +--Site A\n"
"Where A = http://a.com/",
DepictFrameTree(root));
GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
{
RenderFrameDeletedObserver deleted_observer(child->current_frame_host());
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), url));
deleted_observer.WaitUntilDeleted();
}
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(url, observer.last_navigation_url());
ASSERT_EQ(2U, root->child_count());
SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
RenderViewHost* rvh = child->current_frame_host()->render_view_host();
RenderProcessHost* rph = child->current_frame_host()->GetProcess();
EXPECT_NE(shell()->web_contents()->GetPrimaryMainFrame()->GetRenderViewHost(),
rvh);
EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
EXPECT_NE(shell()->web_contents()->GetPrimaryMainFrame()->GetProcess(), rph);
{
std::set<RenderWidgetHostViewBase*> views_set =
web_contents()->GetRenderWidgetHostViewsInWebContentsTree();
EXPECT_EQ(2U, views_set.size());
}
mojo::Remote<mojom::MainFrameCounterTest> main_frame_counter;
shell()->web_contents()->GetPrimaryMainFrame()->GetProcess()->BindReceiver(
main_frame_counter.BindNewPipeAndPassReceiver());
VerifyChildProcessHasMainFrame(main_frame_counter, true);
mojo::Remote<mojom::MainFrameCounterTest> main_frame_counter_child;
rph->BindReceiver(main_frame_counter_child.BindNewPipeAndPassReceiver());
VerifyChildProcessHasMainFrame(main_frame_counter_child, false);
RenderFrameProxyHost* proxy_to_parent =
child->render_manager()->GetProxyToParent();
EXPECT_TRUE(proxy_to_parent);
EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
EXPECT_NE(
rvh->GetWidget()->GetView(),
proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost());
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site B ------- proxies for A\n"
" +--Site A ------- proxies for B\n"
" |--Site A -- proxies for B\n"
" +--Site A -- proxies for B\n"
" +--Site A -- proxies for B\n"
"Where A = http://a.com/\n"
" B = http://foo.com/",
DepictFrameTree(root));
url = embedded_test_server()->GetURL("bar.com", "/title3.html");
{
RenderFrameDeletedObserver deleted_observer(child->current_frame_host());
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), url));
deleted_observer.WaitUntilDeleted();
}
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(url, observer.last_navigation_url());
ASSERT_EQ(2U, root->child_count());
child = root->child_at(0);
EXPECT_NE(shell()->web_contents()->GetPrimaryMainFrame()->GetRenderViewHost(),
child->current_frame_host()->render_view_host());
EXPECT_NE(rvh, child->current_frame_host()->render_view_host());
EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
child->current_frame_host()->GetSiteInstance());
EXPECT_NE(site_instance,
child->current_frame_host()->GetSiteInstance());
EXPECT_NE(shell()->web_contents()->GetPrimaryMainFrame()->GetProcess(),
child->current_frame_host()->GetProcess());
EXPECT_NE(rph, child->current_frame_host()->GetProcess());
VerifyChildProcessHasMainFrame(main_frame_counter, true);
{
std::set<RenderWidgetHostViewBase*> views_set =
web_contents()->GetRenderWidgetHostViewsInWebContentsTree();
EXPECT_EQ(2U, views_set.size());
}
EXPECT_EQ(proxy_to_parent, child->render_manager()->GetProxyToParent());
EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
EXPECT_NE(
child->current_frame_host()->render_view_host()->GetWidget()->GetView(),
proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost());
EXPECT_EQ(
" Site A ------------ proxies for C\n"
" |--Site C ------- proxies for A\n"
" +--Site A ------- proxies for C\n"
" |--Site A -- proxies for C\n"
" +--Site A -- proxies for C\n"
" +--Site A -- proxies for C\n"
"Where A = http://a.com/\n"
" C = http://bar.com/",
DepictFrameTree(root));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
CrossSiteIframeMainFrameCount) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a,a,a(a,a))"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
TestNavigationObserver observer(shell()->web_contents());
EXPECT_EQ(
" Site A\n"
" |--Site A\n"
" |--Site A\n"
" +--Site A\n"
" |--Site A\n"
" +--Site A\n"
"Where A = http://a.com/",
DepictFrameTree(root));
mojo::Remote<mojom::MainFrameCounterTest> main_frame_counter;
shell()->web_contents()->GetPrimaryMainFrame()->GetProcess()->BindReceiver(
main_frame_counter.BindNewPipeAndPassReceiver());
VerifyChildProcessHasMainFrame(main_frame_counter, true);
GURL url = embedded_test_server()->GetURL(
"b.com", "/cross_site_iframe_factory.html?b(a,a)");
{
RenderFrameDeletedObserver deleted_observer(
root->child_at(2)->current_frame_host());
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(2), url));
deleted_observer.WaitUntilDeleted();
}
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"
" |--Site A -- proxies for B\n"
" +--Site A -- proxies for B\n"
"Where A = http://a.com/\n"
" B = http://b.com/",
DepictFrameTree(root));
VerifyChildProcessHasMainFrame(main_frame_counter, true);
mojo::Remote<mojom::MainFrameCounterTest> main_frame_counter_child;
root->child_at(2)->current_frame_host()->GetProcess()->BindReceiver(
main_frame_counter_child.BindNewPipeAndPassReceiver());
VerifyChildProcessHasMainFrame(main_frame_counter_child, false);
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, TitleAfterCrossSiteIframe) {
GURL initial_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), initial_url));
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_TRUE(ExecJs(shell()->web_contents(),
"document.querySelector('iframe').onload = "
" function() { document.title = 'loaded'; };"));
EXPECT_TRUE(
ExecJs(shell()->web_contents(), "document.title = 'not loaded';"));
std::u16string expected_title(u"loaded");
TitleWatcher title_watcher(shell()->web_contents(), expected_title);
TestNavigationObserver load_observer(shell()->web_contents());
GURL frame_url = embedded_test_server()->GetURL("b.com", "/title2.html");
EXPECT_TRUE(ExecJs(root->child_at(0)->current_frame_host(),
JsReplace("window.location.href = $1", frame_url)));
load_observer.Wait();
EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
NavigationEntry* entry =
shell()->web_contents()->GetController().GetLastCommittedEntry();
EXPECT_EQ(expected_title, entry->GetTitle());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
GestureFlingStartEventsBubble) {
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();
ASSERT_EQ(1U, root->child_count());
FrameTreeNode* child_iframe_node = root->child_at(0);
RenderWidgetHost* child_rwh =
child_iframe_node->current_frame_host()->GetRenderWidgetHost();
InputEventAckWaiter gesture_fling_start_ack_observer(
child_rwh, blink::WebInputEvent::Type::kGestureFlingStart);
WaitForHitTestData(child_iframe_node->current_frame_host());
gesture_fling_start_ack_observer.Reset();
GenerateTapDownGesture(child_rwh);
blink::WebGestureEvent gesture_scroll_begin(
blink::WebGestureEvent::Type::kGestureScrollBegin,
blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests(),
blink::WebGestureDevice::kTouchscreen);
gesture_scroll_begin.data.scroll_begin.delta_hint_units =
ui::ScrollGranularity::kScrollByPrecisePixel;
gesture_scroll_begin.data.scroll_begin.delta_x_hint = 0.f;
gesture_scroll_begin.data.scroll_begin.delta_y_hint = 5.f;
child_rwh->ForwardGestureEvent(gesture_scroll_begin);
blink::WebGestureEvent gesture_scroll_update(
blink::WebGestureEvent::Type::kGestureScrollUpdate,
blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests(),
blink::WebGestureDevice::kTouchscreen);
gesture_scroll_update.data.scroll_update.delta_units =
ui::ScrollGranularity::kScrollByPrecisePixel;
gesture_scroll_update.data.scroll_update.delta_x = 0.f;
gesture_scroll_update.data.scroll_update.delta_y = 5.f;
gesture_scroll_update.data.scroll_update.velocity_y = 5.f;
child_rwh->ForwardGestureEvent(gesture_scroll_update);
blink::WebGestureEvent gesture_fling_start(
blink::WebGestureEvent::Type::kGestureFlingStart,
blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests(),
blink::WebGestureDevice::kTouchscreen);
gesture_fling_start.data.fling_start.velocity_x = 0.f;
gesture_fling_start.data.fling_start.velocity_y = 5.f;
child_rwh->ForwardGestureEvent(gesture_fling_start);
gesture_fling_start_ack_observer.Wait();
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
TouchscreenGestureFlingStart) {
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();
ASSERT_EQ(1U, root->child_count());
FrameTreeNode* child_iframe_node = root->child_at(0);
RenderWidgetHost* child_rwh =
child_iframe_node->current_frame_host()->GetRenderWidgetHost();
WaitForHitTestData(child_iframe_node->current_frame_host());
GenerateTapDownGesture(child_rwh);
blink::WebGestureEvent gesture_scroll_begin(
blink::WebGestureEvent::Type::kGestureScrollBegin,
blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests());
gesture_scroll_begin.SetSourceDevice(blink::WebGestureDevice::kTouchscreen);
gesture_scroll_begin.data.scroll_begin.delta_hint_units =
ui::ScrollGranularity::kScrollByPrecisePixel;
gesture_scroll_begin.data.scroll_begin.delta_x_hint = 0.f;
gesture_scroll_begin.data.scroll_begin.delta_y_hint = 5.f;
child_rwh->ForwardGestureEvent(gesture_scroll_begin);
InputEventAckWaiter gesture_scroll_update_ack_observer(
child_rwh, blink::WebInputEvent::Type::kGestureScrollUpdate);
gesture_scroll_update_ack_observer.Reset();
blink::WebGestureEvent gesture_fling_start(
blink::WebGestureEvent::Type::kGestureFlingStart,
blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests());
gesture_fling_start.SetSourceDevice(blink::WebGestureDevice::kTouchscreen);
gesture_fling_start.data.fling_start.velocity_x = 0.f;
gesture_fling_start.data.fling_start.velocity_y = 50.f;
child_rwh->ForwardGestureEvent(gesture_fling_start);
gesture_scroll_update_ack_observer.Wait();
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, TouchpadGestureFlingStart) {
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();
ASSERT_EQ(1U, root->child_count());
FrameTreeNode* child_iframe_node = root->child_at(0);
RenderWidgetHost* child_rwh =
child_iframe_node->current_frame_host()->GetRenderWidgetHost();
InputEventAckWaiter gesture_scroll_begin_ack_observer(
child_rwh, blink::WebInputEvent::Type::kGestureScrollBegin);
blink::WebMouseWheelEvent scroll_event(
blink::WebInputEvent::Type::kMouseWheel,
blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests());
scroll_event.delta_units = ui::ScrollGranularity::kScrollByPrecisePixel;
scroll_event.delta_x = 0.0f;
scroll_event.delta_y = 5.0f;
scroll_event.phase = blink::WebMouseWheelEvent::kPhaseBegan;
child_rwh->ForwardWheelEvent(scroll_event);
gesture_scroll_begin_ack_observer.Wait();
InputEventAckWaiter gesture_scroll_update_ack_observer(
child_rwh, blink::WebInputEvent::Type::kGestureScrollUpdate);
gesture_scroll_update_ack_observer.Reset();
blink::WebGestureEvent gesture_fling_start(
blink::WebGestureEvent::Type::kGestureFlingStart,
blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests());
gesture_fling_start.SetSourceDevice(blink::WebGestureDevice::kTouchpad);
gesture_fling_start.data.fling_start.velocity_x = 0.f;
gesture_fling_start.data.fling_start.velocity_y = 50.f;
child_rwh->ForwardGestureEvent(gesture_fling_start);
gesture_scroll_update_ack_observer.Wait();
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, CompositorFrameSwapped) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(baz)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
ASSERT_EQ(1U, root->child_count());
FrameTreeNode* child_node = root->child_at(0);
GURL site_url(embedded_test_server()->GetURL(
"baz.com", "/cross_site_iframe_factory.html?baz()"));
EXPECT_EQ(site_url, child_node->current_url());
EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
child_node->current_frame_host()->GetSiteInstance());
RenderFrameSubmissionObserver observer(
child_node->current_frame_host()
->GetRenderWidgetHost()
->render_frame_metadata_provider());
observer.WaitForAnyFrameSubmission();
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, CleanupCrossSiteIframe) {
DisableBackForwardCacheForTesting(
web_contents(), content::BackForwardCache::TEST_REQUIRES_NO_CACHING);
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
TestNavigationObserver observer(shell()->web_contents());
GURL foo_url = embedded_test_server()->GetURL("foo.com", "/title2.html");
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), foo_url));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(foo_url, observer.last_navigation_url());
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(1), foo_url));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(foo_url, observer.last_navigation_url());
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site B ------- proxies for A\n"
" +--Site B ------- proxies for A\n"
"Where A = http://a.com/\n"
" B = http://foo.com/",
DepictFrameTree(root));
int subframe_process_id = root->child_at(0)
->current_frame_host()
->GetSiteInstance()
->GetProcess()
->GetID();
int subframe_rvh_id = root->child_at(0)
->current_frame_host()
->render_view_host()
->GetRoutingID();
EXPECT_TRUE(RenderViewHost::FromID(subframe_process_id, subframe_rvh_id));
EXPECT_TRUE(ExecJs(shell(),
"document.body.removeChild("
"document.querySelectorAll('iframe')[0])"));
ASSERT_EQ(1U, root->child_count());
GURL new_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), new_url));
ASSERT_EQ(0U, root->child_count());
EXPECT_FALSE(RenderViewHost::FromID(subframe_process_id, subframe_rvh_id));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, NavigateRemoteFrame) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
TestNavigationObserver observer(shell()->web_contents());
FrameTreeNode* child = root->child_at(0);
GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(child, http_url));
EXPECT_EQ(http_url, observer.last_navigation_url());
EXPECT_TRUE(observer.last_navigation_succeeded());
GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
{
RenderFrameDeletedObserver deleted_observer(child->current_frame_host());
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), url));
deleted_observer.WaitUntilDeleted();
}
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(url, observer.last_navigation_url());
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site B ------- proxies for A\n"
" +--Site A ------- proxies for B\n"
" |--Site A -- proxies for B\n"
" +--Site A -- proxies for B\n"
" +--Site A -- proxies for B\n"
"Where A = http://a.com/\n"
" B = http://foo.com/",
DepictFrameTree(root));
SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
url = embedded_test_server()->GetURL("bar.com", "/title3.html");
{
RenderFrameDeletedObserver deleted_observer(child->current_frame_host());
NavigateIframeToURL(shell()->web_contents(), "child-0", url);
deleted_observer.WaitUntilDeleted();
}
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(url, observer.last_navigation_url());
EXPECT_EQ(
" Site A ------------ proxies for C\n"
" |--Site C ------- proxies for A\n"
" +--Site A ------- proxies for C\n"
" |--Site A -- proxies for C\n"
" +--Site A -- proxies for C\n"
" +--Site A -- proxies for C\n"
"Where A = http://a.com/\n"
" C = http://bar.com/",
DepictFrameTree(root));
{
RenderFrameDeletedObserver deleted_observer(child->current_frame_host());
EXPECT_TRUE(NavigateToURLFromRenderer(child, http_url));
deleted_observer.WaitUntilDeleted();
}
EXPECT_EQ(http_url, observer.last_navigation_url());
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
child->current_frame_host()->GetSiteInstance());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
NavigateRemoteFrameToBlankAndDataURLs) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a,a(a))"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
TestNavigationObserver observer(shell()->web_contents());
FrameTreeNode* child = root->child_at(0);
GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(child, http_url));
EXPECT_EQ(http_url, observer.last_navigation_url());
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(
" Site A\n"
" |--Site A\n"
" +--Site A\n"
" +--Site A\n"
"Where A = http://a.com/",
DepictFrameTree(root));
GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
EXPECT_TRUE(NavigateToURLFromRenderer(child, url));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(url, observer.last_navigation_url());
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site B ------- proxies for A\n"
" +--Site A ------- proxies for B\n"
" +--Site A -- proxies for B\n"
"Where A = http://a.com/\n"
" B = http://foo.com/",
DepictFrameTree(root));
RenderFrameDeletedObserver deleted_observer1(
root->child_at(0)->current_frame_host());
GURL data_url("data:text/html,dataurl");
NavigateIframeToURL(shell()->web_contents(), "child-0", data_url);
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(data_url, observer.last_navigation_url());
deleted_observer1.WaitUntilDeleted();
EXPECT_EQ(
" Site A\n"
" |--Site A\n"
" +--Site A\n"
" +--Site A\n"
"Where A = http://a.com/",
DepictFrameTree(root));
url = embedded_test_server()->GetURL("bar.com", "/title2.html");
EXPECT_TRUE(NavigateToURLFromRenderer(child, url));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(url, observer.last_navigation_url());
EXPECT_EQ(
" Site A ------------ proxies for C\n"
" |--Site C ------- proxies for A\n"
" +--Site A ------- proxies for C\n"
" +--Site A -- proxies for C\n"
"Where A = http://a.com/\n"
" C = http://bar.com/",
DepictFrameTree(root));
RenderFrameDeletedObserver deleted_observer2(
root->child_at(0)->current_frame_host());
GURL about_blank_url("about:blank#foo");
NavigateIframeToURL(shell()->web_contents(), "child-0", about_blank_url);
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(about_blank_url, observer.last_navigation_url());
deleted_observer2.WaitUntilDeleted();
EXPECT_EQ(
" Site A\n"
" |--Site A\n"
" +--Site A\n"
" +--Site A\n"
"Where A = http://a.com/",
DepictFrameTree(root));
url = embedded_test_server()->GetURL("f00.com", "/title3.html");
EXPECT_TRUE(NavigateToURLFromRenderer(child, url));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(url, observer.last_navigation_url());
EXPECT_EQ(
" Site A ------------ proxies for D\n"
" |--Site D ------- proxies for A\n"
" +--Site A ------- proxies for D\n"
" +--Site A -- proxies for D\n"
"Where A = http://a.com/\n"
" D = http://f00.com/",
DepictFrameTree(root));
TestFrameNavigationObserver frame_observer(child);
EXPECT_TRUE(ExecJs(child, "window.location.href = 'about:blank#foo';"));
frame_observer.Wait();
EXPECT_EQ(about_blank_url, child->current_url());
EXPECT_EQ(
" Site A ------------ proxies for D\n"
" |--Site D ------- proxies for A\n"
" +--Site A ------- proxies for D\n"
" +--Site A -- proxies for D\n"
"Where A = http://a.com/\n"
" D = http://f00.com/",
DepictFrameTree(root));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
NavigateRemoteFrameToKilledProcess) {
GURL main_url(embedded_test_server()->GetURL(
"foo.com", "/cross_site_iframe_factory.html?foo.com(bar.com, foo.com)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
TestNavigationObserver observer(shell()->web_contents());
ASSERT_EQ(2U, root->child_count());
GURL site_b_url = embedded_test_server()->GetURL(
"bar.com", "/cross_site_iframe_factory.html?bar.com()");
FrameTreeNode* node2 = root->child_at(0);
EXPECT_EQ(site_b_url, node2->current_url());
RenderProcessHost* child_process = node2->current_frame_host()->GetProcess();
RenderProcessHostWatcher crash_observer(
child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
child_process->Shutdown(0);
crash_observer.Wait();
FrameTreeNode* node3 = root->child_at(1);
EXPECT_TRUE(NavigateToURLFromRenderer(node3, site_b_url));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(site_b_url, observer.last_navigation_url());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, RemoveFocusFromKilledFrame) {
GURL main_url(embedded_test_server()->GetURL(
"foo.com", "/cross_site_iframe_factory.html?foo.com(bar.com)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
TestNavigationObserver observer(shell()->web_contents());
ASSERT_EQ(1U, root->child_count());
GURL site_b_url = embedded_test_server()->GetURL(
"bar.com", "/cross_site_iframe_factory.html?bar.com()");
FrameTreeNode* node2 = root->child_at(0);
EXPECT_EQ(site_b_url, node2->current_url());
web_contents()->SetFocusedFrame(
node2, node2->current_frame_host()->GetSiteInstance()->group());
RenderProcessHost* child_process = node2->current_frame_host()->GetProcess();
RenderProcessHostWatcher crash_observer(
child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
child_process->Shutdown(0);
crash_observer.Wait();
web_contents()->FocusOwningWebContents(
root->current_frame_host()->GetRenderWidgetHost());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
NavigateRemoteFrameToKilledProcessWithSubtree) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(bar(baz), a)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
TestNavigationObserver observer(shell()->web_contents());
ASSERT_EQ(2U, root->child_count());
GURL site_b_url(embedded_test_server()->GetURL(
"bar.com", "/cross_site_iframe_factory.html?bar(baz())"));
EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
root->child_at(0)->current_frame_host()->GetSiteInstance());
EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
root->child_at(1)->current_frame_host()->GetSiteInstance());
ASSERT_EQ(1U, root->child_at(0)->child_count());
FrameTreeNode* node4 = root->child_at(0)->child_at(0);
GURL site_c_url(embedded_test_server()->GetURL(
"baz.com", "/cross_site_iframe_factory.html?baz()"));
EXPECT_EQ(site_c_url, node4->current_url());
{
EXPECT_EQ(
" Site A ------------ proxies for B C\n"
" |--Site B ------- proxies for A C\n"
" | +--Site C -- proxies for A B\n"
" +--Site A ------- proxies for B C\n"
"Where A = http://a.com/\n"
" B = http://bar.com/\n"
" C = http://baz.com/",
DepictFrameTree(root));
RenderProcessHost* child_process_b =
root->child_at(0)->current_frame_host()->GetProcess();
RenderProcessHostWatcher crash_observer(
child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
child_process_b->Shutdown(0);
crash_observer.Wait();
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site B ------- proxies for A\n"
" +--Site A ------- proxies for B\n"
"Where A = http://a.com/\n"
" B = http://bar.com/ (no process)",
DepictFrameTree(root));
}
FrameTreeNode* node3 = root->child_at(1);
GURL url = embedded_test_server()->GetURL("bar.com", "/title1.html");
EXPECT_TRUE(NavigateToURLFromRenderer(node3, url));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(url, observer.last_navigation_url());
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site B ------- proxies for A\n"
" +--Site B ------- proxies for A\n"
"Where A = http://a.com/\n"
" B = http://bar.com/",
DepictFrameTree(root));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, NavigateRemoteAfterError) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
{
TestNavigationObserver observer(shell()->web_contents());
FrameTreeNode* child = root->child_at(0);
GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(child, http_url));
EXPECT_EQ(http_url, observer.last_navigation_url());
EXPECT_TRUE(observer.last_navigation_succeeded());
observer.Wait();
}
{
TestNavigationObserver observer(shell()->web_contents());
FrameTreeNode* child = root->child_at(0);
GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), url));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(url, observer.last_navigation_url());
observer.Wait();
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" +--Site B ------- proxies for A\n"
"Where A = http://a.com/\n"
" B = http://foo.com/",
DepictFrameTree(root));
SiteInstance* site_instance =
child->current_frame_host()->GetSiteInstance();
EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
}
{
GURL url = embedded_test_server()->GetURL("bar.com", "/title3.html");
EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
NavigateIframeToURL(shell()->web_contents(), "child-0", url);
}
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, ProcessTransferAfterError) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child = root->child_at(0);
GURL url_a = child->current_url();
GURL url_b = embedded_test_server()->GetURL("b.com", "/title3.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;
}));
TestNavigationObserver observer(shell()->web_contents());
NavigateIframeToURL(shell()->web_contents(), "child-0", url_b);
EXPECT_FALSE(observer.last_navigation_succeeded());
EXPECT_EQ(url_b, observer.last_navigation_url());
EXPECT_EQ(2, shell()->web_contents()->GetController().GetEntryCount());
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" +--Site B ------- proxies for A\n"
"Where A = http://a.com/\n"
" B = http://b.com/",
DepictFrameTree(root));
EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
child->current_frame_host()->GetSiteInstance());
EXPECT_EQ(GURL(), child->current_frame_host()->last_successful_url());
EXPECT_EQ(url_b, child->current_url());
EXPECT_EQ("null", child->current_origin().Serialize());
url_loader_interceptor.reset();
EXPECT_TRUE(ExecJs(root, "// No-op script"));
NavigateIframeToURL(shell()->web_contents(), "child-0", url_b);
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(url_b, observer.last_navigation_url());
EXPECT_EQ(url_b, child->current_frame_host()->last_successful_url());
EXPECT_EQ(url_b, child->current_url());
EXPECT_EQ(url_b.DeprecatedGetOriginAsURL().spec(),
child->current_origin().Serialize() + '/');
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" +--Site B ------- proxies for A\n"
"Where A = http://a.com/\n"
" B = http://b.com/",
DepictFrameTree(root));
EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
child->current_frame_host()->GetSiteInstance());
EXPECT_EQ(2, shell()->web_contents()->GetController().GetEntryCount());
{
RenderFrameDeletedObserver deleted_observer(child->current_frame_host());
TestNavigationObserver back_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoBack();
back_load_observer.Wait();
deleted_observer.WaitUntilDeleted();
}
EXPECT_EQ(
" Site A\n"
" +--Site A\n"
"Where A = http://a.com/",
DepictFrameTree(root));
EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
child->current_frame_host()->GetSiteInstance());
EXPECT_EQ(url_a, child->current_frame_host()->last_successful_url());
EXPECT_EQ(url_a, child->current_url());
EXPECT_EQ(url_a.DeprecatedGetOriginAsURL().spec(),
child->current_origin().Serialize() + '/');
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
NavigatingToKilledProcessRestoresAllProxies) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/frame_tree/page_with_three_frames.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
TestNavigationObserver observer(shell()->web_contents());
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site B ------- proxies for A\n"
" |--Site A ------- proxies for B\n"
" +--Site A ------- proxies for B\n"
"Where A = http://a.com/\n"
" B = http://b.com/",
DepictFrameTree(root));
RenderProcessHost* child_process =
root->child_at(0)->current_frame_host()->GetProcess();
RenderProcessHostWatcher crash_observer(
child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
child_process->Shutdown(0);
crash_observer.Wait();
GURL b_url = embedded_test_server()->GetURL("b.com", "/post_message.html");
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(1), b_url));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(b_url, observer.last_navigation_url());
EXPECT_TRUE(root->child_at(1)->current_frame_host()->IsRenderFrameLive());
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site B ------- proxies for A\n"
" |--Site B ------- proxies for A\n"
" +--Site A ------- proxies for B\n"
"Where A = http://a.com/\n"
" B = http://b.com/",
DepictFrameTree(root));
PostMessageAndWaitForReply(root->child_at(1),
"postToSibling('subframe-msg','frame3')",
"\"done-frame2\"");
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
CreateChildFrameAfterKillingProcess) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/frame_tree/page_with_three_frames.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site B ------- proxies for A\n"
" |--Site A ------- proxies for B\n"
" +--Site A ------- proxies for B\n"
"Where A = http://a.com/\n"
" B = http://b.com/",
DepictFrameTree(root));
SiteInstanceImpl* b_site_instance =
root->child_at(0)->current_frame_host()->GetSiteInstance();
RenderProcessHost* child_process =
root->child_at(0)->current_frame_host()->GetProcess();
RenderProcessHostWatcher crash_observer(
child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
child_process->Shutdown(0);
crash_observer.Wait();
RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1);
EXPECT_TRUE(
ExecJs(root->child_at(2),
"document.body.appendChild(document.createElement('iframe'));"));
frame_observer.Wait();
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site B ------- proxies for A\n"
" |--Site A ------- proxies for B\n"
" +--Site A ------- proxies for B\n"
" +--Site A -- proxies for B\n"
"Where A = http://a.com/\n"
" B = http://b.com/ (no process)",
DepictFrameTree(root));
FrameTreeNode* grandchild = root->child_at(2)->child_at(0);
RenderFrameProxyHost* grandchild_rfph =
grandchild->current_frame_host()
->browsing_context_state()
->GetRenderFrameProxyHost(b_site_instance->group());
EXPECT_FALSE(grandchild_rfph->is_render_frame_proxy_live());
TestNavigationObserver observer(shell()->web_contents());
GURL b_url = embedded_test_server()->GetURL("b.com", "/title1.html");
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(1), b_url));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(b_url, observer.last_navigation_url());
EXPECT_TRUE(grandchild_rfph->is_render_frame_proxy_live());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
CreateChildFrameAfterKillingOpener) {
GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
SiteInstanceImpl* site_instance_a =
root->current_frame_host()->GetSiteInstance();
ShellAddedObserver new_shell_observer;
EXPECT_TRUE(ExecJs(root, "popup = window.open('about:blank');"));
Shell* popup = new_shell_observer.GetShell();
GURL popup_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(popup, popup_url));
FrameTreeNode* popup_root =
static_cast<WebContentsImpl*>(popup->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(
" Site A ------------ proxies for B\n"
"Where A = http://a.com/\n"
" B = http://b.com/",
DepictFrameTree(root));
EXPECT_EQ(
" Site B ------------ proxies for A\n"
"Where A = http://a.com/\n"
" B = http://b.com/",
DepictFrameTree(popup_root));
RenderProcessHost* child_process = root->current_frame_host()->GetProcess();
RenderProcessHostWatcher crash_observer(
child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
child_process->Shutdown(0);
crash_observer.Wait();
EXPECT_FALSE(root->current_frame_host()->IsRenderFrameLive());
RenderFrameProxyHost* rfph =
popup_root->current_frame_host()
->browsing_context_state()
->GetRenderFrameProxyHost(site_instance_a->group());
EXPECT_FALSE(rfph->is_render_frame_proxy_live());
EXPECT_TRUE(NavigateToURL(shell(), main_url));
EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
EXPECT_FALSE(rfph->is_render_frame_proxy_live());
RenderFrameHostCreatedObserver frame_observer(popup->web_contents(), 1);
EXPECT_TRUE(ExecJs(
popup, "document.body.appendChild(document.createElement('iframe'));"));
frame_observer.Wait();
EXPECT_FALSE(rfph->is_render_frame_proxy_live());
RenderFrameProxyHost* child_rfph =
popup_root->child_at(0)
->current_frame_host()
->browsing_context_state()
->GetRenderFrameProxyHost(site_instance_a->group());
EXPECT_TRUE(child_rfph);
EXPECT_FALSE(child_rfph->is_render_frame_proxy_live());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
KillingRendererClearsDescendantProxies) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/frame_tree/page_with_two_frames_nested.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
ASSERT_EQ(2U, root->child_count());
GURL site_b_url(embedded_test_server()->GetURL(
"bar.com", "/frame_tree/page_with_one_frame.html"));
EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
root->child_at(0)->current_frame_host()->GetSiteInstance());
EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
root->child_at(1)->current_frame_host()->GetSiteInstance());
ASSERT_EQ(1U, root->child_at(0)->child_count());
FrameTreeNode* node4 = root->child_at(0)->child_at(0);
GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
EXPECT_EQ(site_c_url, node4->current_url());
scoped_refptr<SiteInstanceGroup> site_instance_c_group =
node4->current_frame_host()->GetSiteInstance()->group();
EXPECT_EQ(
" Site A ------------ proxies for B C\n"
" |--Site B ------- proxies for A C\n"
" | +--Site C -- proxies for A B\n"
" +--Site A ------- proxies for B C\n"
"Where A = http://a.com/\n"
" B = http://bar.com/\n"
" C = http://baz.com/",
DepictFrameTree(root));
EXPECT_GT(site_instance_c_group->active_frame_count(), 0U);
RenderProcessHost* child_process_b =
root->child_at(0)->current_frame_host()->GetProcess();
RenderProcessHostWatcher crash_observer(
child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
child_process_b->Shutdown(0);
crash_observer.Wait();
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site B ------- proxies for A\n"
" +--Site A ------- proxies for B\n"
"Where A = http://a.com/\n"
" B = http://bar.com/ (no process)",
DepictFrameTree(root));
EXPECT_EQ(0U, site_instance_c_group->active_frame_count());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, CrashSubframe) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" +--Site B ------- proxies for A\n"
"Where A = http://a.com/\n"
" B = http://b.com/",
DepictFrameTree(root));
FrameTreeNode* child = root->child_at(0);
EXPECT_TRUE(
child->current_frame_host()->render_view_host()->IsRenderViewLive());
EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive());
RenderProcessHost* root_process = root->current_frame_host()->GetProcess();
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();
}
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" +--Site B ------- proxies for A\n"
"Where A = http://a.com/\n"
" B = http://b.com/ (no process)",
DepictFrameTree(root));
EXPECT_EQ(1U, root->child_count());
EXPECT_EQ(main_url, root->current_url());
EXPECT_EQ(GURL(), child->current_url());
EXPECT_FALSE(
child->current_frame_host()->render_view_host()->IsRenderViewLive());
EXPECT_FALSE(child->current_frame_host()->IsRenderFrameLive());
{
RenderProcessHostWatcher crash_observer(
root_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
root_process->Shutdown(0);
crash_observer.Wait();
}
EXPECT_EQ(0U, root->child_count());
EXPECT_EQ(GURL(), root->current_url());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, CreateProxiesForNewFrames) {
GURL main_url(embedded_test_server()->GetURL(
"b.com", "/frame_tree/page_with_one_frame.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
ASSERT_EQ(1U, root->child_count());
EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
root->child_at(0)->current_url());
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" +--Site B ------- proxies for A\n"
"Where A = http://b.com/\n"
" B = http://baz.com/",
DepictFrameTree(root));
RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1);
EXPECT_TRUE(ExecJs(shell(), "addFrame('data:text/html,foo');"));
frame_observer.Wait();
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site B ------- proxies for A\n"
" +--Site A ------- proxies for B\n"
"Where A = http://b.com/\n"
" B = http://baz.com/",
DepictFrameTree(root));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
DISABLED_CrossSiteIframeRedirectOnce) {
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_server.ServeFilesFromSourceDirectory(GetTestDataFilePath());
ASSERT_TRUE(https_server.Start());
GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
GURL http_url(embedded_test_server()->GetURL("/title1.html"));
GURL https_url(https_server.GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
TestNavigationObserver observer(shell()->web_contents());
{
GURL client_redirect_https_url(
https_server.GetURL("/client-redirect?/title1.html"));
EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
client_redirect_https_url));
EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
EXPECT_FALSE(observer.last_navigation_succeeded());
}
{
GURL server_redirect_http_url(
https_server.GetURL("/server-redirect?" + http_url.spec()));
EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
server_redirect_http_url));
EXPECT_EQ(observer.last_navigation_url(), http_url);
EXPECT_TRUE(observer.last_navigation_succeeded());
}
{
GURL server_redirect_http_url(
https_server.GetURL("/server-redirect?/title1.html"));
EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
server_redirect_http_url));
EXPECT_EQ(observer.last_navigation_url(), https_url);
EXPECT_FALSE(observer.last_navigation_succeeded());
}
{
GURL server_redirect_http_url(
embedded_test_server()->GetURL("/server-redirect?" + https_url.spec()));
EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
server_redirect_http_url));
EXPECT_EQ(observer.last_navigation_url(), https_url);
EXPECT_FALSE(observer.last_navigation_succeeded());
}
{
GURL client_redirect_http_url(
embedded_test_server()->GetURL("/client-redirect?" + https_url.spec()));
LoadStopObserver load_observer2(shell()->web_contents());
EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
client_redirect_http_url));
EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
EXPECT_TRUE(observer.last_navigation_succeeded());
load_observer2.Wait();
EXPECT_EQ(observer.last_navigation_url(), https_url);
EXPECT_FALSE(observer.last_navigation_succeeded());
}
{
GURL server_redirect_http_url(
embedded_test_server()->GetURL("/server-redirect?/title1.html"));
EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
server_redirect_http_url));
EXPECT_EQ(observer.last_navigation_url(), http_url);
EXPECT_TRUE(observer.last_navigation_succeeded());
}
{
GURL client_redirect_http_url(
embedded_test_server()->GetURL("/client-redirect?" + http_url.spec()));
LoadStopObserver load_observer2(shell()->web_contents());
EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
client_redirect_http_url));
EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
EXPECT_TRUE(observer.last_navigation_succeeded());
load_observer2.Wait();
EXPECT_EQ(observer.last_navigation_url(), http_url);
EXPECT_TRUE(observer.last_navigation_succeeded());
}
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
DISABLED_CrossSiteIframeRedirectTwice) {
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_server.ServeFilesFromSourceDirectory(GetTestDataFilePath());
ASSERT_TRUE(https_server.Start());
GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
GURL http_url(embedded_test_server()->GetURL("/title1.html"));
GURL https_url(https_server.GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
TestNavigationObserver observer(shell()->web_contents());
{
GURL client_redirect_https_url(
https_server.GetURL("/client-redirect?" + http_url.spec()));
GURL client_redirect_http_url(embedded_test_server()->GetURL(
"/client-redirect?" + client_redirect_https_url.spec()));
LoadStopObserver load_observer2(shell()->web_contents());
EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
client_redirect_http_url));
load_observer2.Wait();
EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
EXPECT_FALSE(observer.last_navigation_succeeded());
}
{
GURL server_redirect_https_url(
https_server.GetURL("/server-redirect?" + http_url.spec()));
GURL server_redirect_http_url(embedded_test_server()->GetURL(
"/server-redirect?" + server_redirect_https_url.spec()));
EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
server_redirect_http_url));
EXPECT_EQ(observer.last_navigation_url(), http_url);
EXPECT_TRUE(observer.last_navigation_succeeded());
}
{
GURL server_redirect_https_url(
https_server.GetURL("/server-redirect?" + https_url.spec()));
GURL server_redirect_http_url(embedded_test_server()->GetURL(
"/server-redirect?" + server_redirect_https_url.spec()));
EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
server_redirect_http_url));
EXPECT_EQ(observer.last_navigation_url(), https_url);
EXPECT_FALSE(observer.last_navigation_succeeded());
}
{
GURL client_redirect_http_url(
https_server.GetURL("/client-redirect?" + http_url.spec()));
GURL server_redirect_http_url(embedded_test_server()->GetURL(
"/server-redirect?" + client_redirect_http_url.spec()));
EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
server_redirect_http_url));
EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
EXPECT_FALSE(observer.last_navigation_succeeded());
}
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, ProxyCreationSkipsSubtree) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_TRUE(root->child_at(1) != nullptr);
EXPECT_EQ(2U, root->child_at(1)->child_count());
{
TestNavigationObserver observer(shell()->web_contents());
GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), http_url));
EXPECT_EQ(http_url, observer.last_navigation_url());
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(
" Site A\n"
" |--Site A\n"
" +--Site A\n"
" |--Site A\n"
" +--Site A\n"
" +--Site A\n"
"Where A = http://a.com/",
DepictFrameTree(root));
}
GURL cross_site_url =
embedded_test_server()->GetURL("foo.com", "/frame_tree/title2.html");
FrameTreeNode* child = root->child_at(1);
SiteInstance* site = nullptr;
std::string cross_site_rfh_type = "speculative";
{
TestNavigationObserver observer(shell()->web_contents());
TestFrameNavigationObserver navigation_observer(child);
NavigationController::LoadURLParams params(cross_site_url);
params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
params.frame_tree_node_id = child->frame_tree_node_id();
child->navigator().controller().LoadURLWithParams(params);
site = child->render_manager()->speculative_frame_host()->GetSiteInstance();
EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site);
std::string tree = base::StringPrintf(
" Site A ------------ proxies for B\n"
" |--Site A ------- proxies for B\n"
" +--Site A (B %s) -- proxies for B\n"
" |--Site A\n"
" +--Site A\n"
" +--Site A\n"
"Where A = http://a.com/\n"
" B = http://foo.com/",
cross_site_rfh_type.c_str());
EXPECT_EQ(tree, DepictFrameTree(root));
navigation_observer.Wait();
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(cross_site_url, observer.last_navigation_url());
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site A ------- proxies for B\n"
" +--Site B ------- proxies for A\n"
"Where A = http://a.com/\n"
" B = http://foo.com/",
DepictFrameTree(root));
}
cross_site_url = embedded_test_server()->GetURL("bar.com", "/title3.html");
{
TestNavigationObserver observer(shell()->web_contents());
TestFrameNavigationObserver navigation_observer(child);
NavigationController::LoadURLParams params(cross_site_url);
params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
params.frame_tree_node_id = child->frame_tree_node_id();
child->navigator().controller().LoadURLWithParams(params);
SiteInstance* site2 =
child->render_manager()->speculative_frame_host()->GetSiteInstance();
EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2);
EXPECT_NE(site, site2);
std::string tree = base::StringPrintf(
" Site A ------------ proxies for B C\n"
" |--Site A ------- proxies for B C\n"
" +--Site B (C %s) -- proxies for A C\n"
"Where A = http://a.com/\n"
" B = http://foo.com/\n"
" C = http://bar.com/",
cross_site_rfh_type.c_str());
EXPECT_EQ(tree, DepictFrameTree(root));
navigation_observer.Wait();
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(cross_site_url, observer.last_navigation_url());
EXPECT_EQ(0U, child->child_count());
}
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, OriginReplication) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b(c(a),b), a)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(
" Site A ------------ proxies for B C\n"
" |--Site B ------- proxies for A C\n"
" | |--Site C -- proxies for A B\n"
" | | +--Site A -- proxies for B C\n"
" | +--Site B -- proxies for A C\n"
" +--Site A ------- proxies for B C\n"
"Where A = http://a.com/\n"
" B = http://b.com/\n"
" C = http://c.com/",
DepictFrameTree(root));
url::Origin a_origin =
url::Origin::Create(embedded_test_server()->GetURL("a.com", "/"));
url::Origin b_origin =
url::Origin::Create(embedded_test_server()->GetURL("b.com", "/"));
url::Origin c_origin =
url::Origin::Create(embedded_test_server()->GetURL("c.com", "/"));
FrameTreeNode* tiptop_child = root->child_at(0);
FrameTreeNode* middle_child = root->child_at(0)->child_at(0);
FrameTreeNode* lowest_child = root->child_at(0)->child_at(0)->child_at(0);
EXPECT_EQ(ListValueOf(a_origin),
EvalJs(tiptop_child, "Array.from(location.ancestorOrigins);"));
EXPECT_EQ(ListValueOf(b_origin, a_origin),
EvalJs(middle_child, "Array.from(location.ancestorOrigins);"));
EXPECT_EQ(ListValueOf(c_origin, b_origin, a_origin),
EvalJs(lowest_child, "Array.from(location.ancestorOrigins);"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessAutoplayBrowserTest,
DISABLED_PropagateUserGestureFlag) {
GURL main_url(embedded_test_server()->GetURL(
"example.com", "/media/autoplay/autoplay-enabled.html"));
GURL foo_url(embedded_test_server()->GetURL(
"foo.com", "/media/autoplay/autoplay-enabled.html"));
GURL bar_url(embedded_test_server()->GetURL(
"bar.com", "/media/autoplay/autoplay-enabled.html"));
GURL secondary_url(embedded_test_server()->GetURL(
"test.example.com", "/media/autoplay/autoplay-enabled.html"));
GURL disabled_url(embedded_test_server()->GetURL(
"test.example.com", "/media/autoplay/autoplay-disabled.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_TRUE(NavigateFrameToURL(root->child_at(0), foo_url));
EXPECT_TRUE(NavigateFrameToURL(root->child_at(0)->child_at(0), bar_url));
EXPECT_TRUE(AutoplayAllowed(shell(), true));
EXPECT_TRUE(AutoplayAllowed(root->child_at(0), false));
EXPECT_TRUE(AutoplayAllowed(root->child_at(0)->child_at(0), false));
EXPECT_TRUE(NavigateToURLFromRenderer(shell(), secondary_url));
root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_TRUE(NavigateFrameToURL(root->child_at(0), foo_url));
EXPECT_TRUE(NavigateFrameToURL(root->child_at(0)->child_at(0), bar_url));
EXPECT_TRUE(AutoplayAllowed(shell(), false));
EXPECT_TRUE(AutoplayAllowed(root->child_at(0), false));
EXPECT_TRUE(AutoplayAllowed(root->child_at(0)->child_at(0), false));
EXPECT_TRUE(NavigateToURLFromRenderer(shell(), disabled_url));
EXPECT_TRUE(NavigateFrameToURL(root->child_at(0), foo_url));
EXPECT_TRUE(AutoplayAllowed(shell(), false));
EXPECT_FALSE(AutoplayAllowed(root->child_at(0), false));
EXPECT_TRUE(NavigateToURLFromRenderer(shell(), foo_url));
EXPECT_TRUE(NavigateFrameToURL(root->child_at(0), bar_url));
EXPECT_FALSE(AutoplayAllowed(shell(), false));
EXPECT_FALSE(AutoplayAllowed(shell(), false));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, SandboxFlagsReplication) {
GURL main_url(embedded_test_server()->GetURL("/sandboxed_frames.html"));
const url::Origin main_origin = url::Origin::Create(main_url);
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
TestNavigationObserver observer(shell()->web_contents());
GURL foo_url(
embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(1), foo_url));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(foo_url, root->child_at(1)->current_url());
ASSERT_EQ(2U, root->child_at(1)->child_count());
GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
EXPECT_TRUE(
NavigateToURLFromRenderer(root->child_at(1)->child_at(0), bar_url));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(bar_url, observer.last_navigation_url());
EXPECT_EQ(false, EvalJs(root->child_at(1),
"!!window.open('data:text/html,dataurl');"));
EXPECT_EQ(1u, Shell::windows().size());
EXPECT_EQ(false, EvalJs(root->child_at(1)->child_at(0),
"!!window.open('data:text/html,dataurl');"));
EXPECT_EQ(1u, Shell::windows().size());
EXPECT_EQ(false, EvalJs(root->child_at(2)->child_at(0),
"!!window.open('data:text/html,dataurl');"));
EXPECT_EQ(1u, Shell::windows().size());
EXPECT_EQ(ListValueOf(main_origin),
EvalJs(root->child_at(1), "Array.from(location.ancestorOrigins);"));
EXPECT_EQ(ListValueOf("null", main_origin),
EvalJs(root->child_at(1)->child_at(0),
"Array.from(location.ancestorOrigins);"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, DynamicSandboxFlags) {
GURL main_url(
embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
TestNavigationObserver observer(shell()->web_contents());
ASSERT_EQ(2U, root->child_count());
EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
root->child_at(0)->current_url());
GURL baz_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(1), baz_url));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(baz_url, observer.last_navigation_url());
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
root->child_at(0)->pending_frame_policy().sandbox_flags);
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
root->child_at(0)->effective_frame_policy().sandbox_flags);
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
root->child_at(1)->pending_frame_policy().sandbox_flags);
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
root->child_at(1)->effective_frame_policy().sandbox_flags);
EXPECT_TRUE(ExecJs(
shell(), "document.querySelector('iframe').sandbox='allow-scripts';"));
network::mojom::WebSandboxFlags expected_flags =
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kAutomaticFeatures;
EXPECT_EQ(expected_flags,
root->child_at(0)->pending_frame_policy().sandbox_flags);
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
root->child_at(0)->effective_frame_policy().sandbox_flags);
GURL bar_url(
embedded_test_server()->GetURL("bar.com", "/frame_tree/2-4.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), bar_url));
ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(bar_url, root->child_at(0)->current_url());
ASSERT_EQ(1U, root->child_at(0)->child_count());
EXPECT_EQ(
" Site A ------------ proxies for B C\n"
" |--Site B ------- proxies for A C\n"
" | +--Site B -- proxies for A C\n"
" +--Site C ------- proxies for A B\n"
"Where A = http://127.0.0.1/\n"
" B = http://bar.com/\n"
" C = http://baz.com/",
DepictFrameTree(root));
EXPECT_EQ(expected_flags,
root->child_at(0)->pending_frame_policy().sandbox_flags);
EXPECT_EQ(expected_flags,
root->child_at(0)->effective_frame_policy().sandbox_flags);
EXPECT_EQ(false, EvalJs(root->child_at(0),
"!!window.open('data:text/html,dataurl');"));
EXPECT_EQ(1u, Shell::windows().size());
GURL baz_child_url(embedded_test_server()->GetURL("baz.com", "/title2.html"));
EXPECT_TRUE(
NavigateToURLFromRenderer(root->child_at(0)->child_at(0), baz_child_url));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(baz_child_url, observer.last_navigation_url());
EXPECT_EQ(
" Site A ------------ proxies for B C\n"
" |--Site B ------- proxies for A C\n"
" | +--Site C -- proxies for A B\n"
" +--Site C ------- proxies for A B\n"
"Where A = http://127.0.0.1/\n"
" B = http://bar.com/\n"
" C = http://baz.com/",
DepictFrameTree(root));
EXPECT_EQ(false, EvalJs(root->child_at(0)->child_at(0),
"!!window.open('data:text/html,dataurl');"));
EXPECT_EQ(1u, Shell::windows().size());
EXPECT_EQ(
expected_flags,
root->child_at(0)->child_at(0)->effective_frame_policy().sandbox_flags);
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
DynamicSandboxFlagsRemoteToLocal) {
GURL main_url(
embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
TestNavigationObserver observer(shell()->web_contents());
ASSERT_EQ(2U, root->child_count());
EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
root->child_at(0)->current_url());
EXPECT_EQ(embedded_test_server()->GetURL("/title1.html"),
root->child_at(1)->current_url());
EXPECT_TRUE(
ExecJs(shell(),
"document.querySelectorAll('iframe')[1].sandbox='allow-scripts'"));
network::mojom::WebSandboxFlags expected_flags =
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kAutomaticFeatures;
EXPECT_EQ(expected_flags,
root->child_at(1)->pending_frame_policy().sandbox_flags);
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
root->child_at(1)->effective_frame_policy().sandbox_flags);
GURL bar_url(embedded_test_server()->GetURL(
"bar.com", "/frame_tree/page_with_one_frame.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(1), bar_url));
EXPECT_EQ(bar_url, root->child_at(1)->current_url());
ASSERT_EQ(1U, root->child_at(1)->child_count());
EXPECT_EQ(expected_flags,
root->child_at(1)->pending_frame_policy().sandbox_flags);
EXPECT_EQ(expected_flags,
root->child_at(1)->effective_frame_policy().sandbox_flags);
EXPECT_EQ(false, EvalJs(root->child_at(1),
"!!window.open('data:text/html,dataurl');"));
EXPECT_EQ(1u, Shell::windows().size());
EXPECT_EQ(false, EvalJs(root->child_at(1)->child_at(0),
"!!window.open('data:text/html,dataurl');"));
EXPECT_EQ(1u, Shell::windows().size());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
DynamicSandboxFlagsRendererInitiatedNavigation) {
GURL main_url(
embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
TestNavigationObserver observer(shell()->web_contents());
ASSERT_EQ(1U, root->child_count());
EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
root->child_at(0)->current_url());
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
root->child_at(0)->pending_frame_policy().sandbox_flags);
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
root->child_at(0)->effective_frame_policy().sandbox_flags);
EXPECT_TRUE(ExecJs(
shell(), "document.querySelector('iframe').sandbox='allow-scripts';"));
network::mojom::WebSandboxFlags expected_flags =
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kAutomaticFeatures;
EXPECT_EQ(expected_flags,
root->child_at(0)->pending_frame_policy().sandbox_flags);
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
root->child_at(0)->effective_frame_policy().sandbox_flags);
TestFrameNavigationObserver frame_observer(root->child_at(0));
ASSERT_TRUE(ExecJs(root->child_at(0), "window.location.href='/title2.html'"));
frame_observer.Wait();
EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title2.html"),
root->child_at(0)->current_url());
EXPECT_EQ(expected_flags,
root->child_at(0)->pending_frame_policy().sandbox_flags);
EXPECT_EQ(expected_flags,
root->child_at(0)->effective_frame_policy().sandbox_flags);
EXPECT_EQ(false, EvalJs(root->child_at(0),
"!!window.open('data:text/html,dataurl');"));
EXPECT_EQ(1u, Shell::windows().size());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
ProxiesForNewChildFramesHaveCorrectReplicationState) {
GURL main_url(
embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(
" 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));
RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 3);
EXPECT_TRUE(ExecJs(root,
"addFrame('/frame_tree/page_with_one_frame.html',"
" 'allow-scripts allow-same-origin')"));
frame_observer.Wait();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
FrameTreeNode* bottom_child = root->child_at(1)->child_at(0);
EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
bottom_child->current_url());
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site B ------- proxies for A\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));
EXPECT_EQ(
ListValueOf(url::Origin::Create(main_url), url::Origin::Create(main_url)),
EvalJs(bottom_child, "Array.from(location.ancestorOrigins);"));
network::mojom::WebSandboxFlags expected_flags =
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kAutomaticFeatures &
~network::mojom::WebSandboxFlags::kOrigin;
EXPECT_EQ(expected_flags,
root->child_at(1)->effective_frame_policy().sandbox_flags);
EXPECT_EQ(expected_flags,
bottom_child->effective_frame_policy().sandbox_flags);
EXPECT_EQ(false,
EvalJs(bottom_child, "!!window.open('data:text/html,dataurl')"));
EXPECT_EQ(1u, Shell::windows().size());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, WindowNameReplication) {
GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
TestNavigationObserver observer(shell()->web_contents());
GURL frame_url =
embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(frame_url, observer.last_navigation_url());
EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
root->child_at(0)->current_frame_host()->GetSiteInstance());
EXPECT_EQ("3-1-name", EvalJs(root->child_at(0), "window.name;"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, DynamicWindowName) {
GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
TestNavigationObserver observer(shell()->web_contents());
GURL frame_url =
embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(frame_url, observer.last_navigation_url());
EXPECT_EQ(root->child_at(0)->frame_name(), "3-1-name");
EXPECT_TRUE(ExecJs(root->child_at(0), "window.name = 'updated-name';"));
EXPECT_EQ(root->child_at(0)->frame_name(), "updated-name");
EXPECT_EQ(true, EvalJs(shell(), "frames['updated-name'] === undefined;"));
EXPECT_TRUE(ExecJs(root, "window['3-1-id'].name = 'updated-name';"));
EXPECT_EQ(true, EvalJs(shell(), "frames['updated-name'] == frames[0];"));
TestFrameNavigationObserver frame_observer(root->child_at(0));
GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
EXPECT_TRUE(
ExecJs(shell(),
JsReplace("frames['updated-name'].location.href = $1", foo_url)));
frame_observer.Wait();
EXPECT_EQ(foo_url, root->child_at(0)->current_url());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, OriginUpdatesReachProxies) {
GURL main_url(
embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
TestNavigationObserver observer(shell()->web_contents());
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site B ------- proxies for A\n"
" +--Site A ------- proxies for B\n"
"Where A = http://127.0.0.1/\n"
" B = http://bar.com/",
DepictFrameTree(root));
GURL frame_url = embedded_test_server()->GetURL("baz.com", "/title2.html");
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(1), frame_url));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(frame_url, observer.last_navigation_url());
WebContentsConsoleObserver console_observer(shell()->web_contents());
console_observer.SetPattern("Unsafe attempt to initiate navigation*");
EXPECT_TRUE(ExecJs(root->child_at(0),
"try { parent.frames['frame2'].location.href = "
"'data:text/html,foo'; } catch (e) {}"));
ASSERT_TRUE(console_observer.Wait());
std::string frame_origin = root->child_at(1)->current_origin().Serialize();
EXPECT_EQ(frame_origin + "/", frame_url.DeprecatedGetOriginAsURL().spec());
EXPECT_TRUE(base::MatchPattern(console_observer.GetMessageAt(0u),
"*" + frame_origin + "*"))
<< "Error message does not contain the frame's latest origin ("
<< frame_origin << ")";
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, CrossSiteDidStopLoading) {
GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
TestNavigationObserver observer(shell()->web_contents());
FrameTreeNode* child = root->child_at(0);
GURL http_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(child, http_url));
EXPECT_EQ(http_url, observer.last_navigation_url());
EXPECT_TRUE(observer.last_navigation_succeeded());
TestNavigationObserver nav_observer(shell()->web_contents(), 1);
GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
NavigationController::LoadURLParams params(url);
params.transition_type = ui::PAGE_TRANSITION_LINK;
params.frame_tree_node_id = child->frame_tree_node_id();
child->navigator().controller().LoadURLWithParams(params);
nav_observer.Wait();
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(url, observer.last_navigation_url());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
NavigateWithSiblingRemoteFrame) {
GURL main_url(
embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
TestNavigationObserver observer(shell()->web_contents());
ASSERT_EQ(2U, root->child_count());
FrameTreeNode* node2 = root->child_at(0);
EXPECT_NE(root->current_frame_host()->GetSiteInstance(),
node2->current_frame_host()->GetSiteInstance());
FrameTreeNode* node3 = root->child_at(1);
EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
node3->current_frame_host()->GetSiteInstance());
GURL title_url = embedded_test_server()->GetURL("/title2.html");
EXPECT_TRUE(NavigateToURLFromRenderer(node3, title_url));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(title_url, observer.last_navigation_url());
EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
node3->current_frame_host()->GetSiteInstance());
EXPECT_TRUE(node3->current_frame_host()->IsRenderFrameLive());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
NavigateSiblingsToSameProcess) {
GURL main_url(
embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* node2 = root->child_at(0);
FrameTreeNode* node3 = root->child_at(1);
GURL frame_url = embedded_test_server()->GetURL("bar.com", "/title1.html");
EXPECT_TRUE(NavigateToURLFromRenderer(node3, frame_url));
EXPECT_EQ(node2->current_frame_host()->GetSiteInstance(),
node3->current_frame_host()->GetSiteInstance());
EXPECT_NE(root->current_frame_host()->GetSiteInstance(),
node3->current_frame_host()->GetSiteInstance());
GURL title_url = embedded_test_server()->GetURL("/title2.html");
EXPECT_TRUE(NavigateToURLFromRenderer(node2, title_url));
EXPECT_NE(node2->current_frame_host()->GetSiteInstance(),
node3->current_frame_host()->GetSiteInstance());
EXPECT_TRUE(NavigateToURLFromRenderer(node2, frame_url));
EXPECT_EQ(node2->current_frame_host()->GetSiteInstance(),
node3->current_frame_host()->GetSiteInstance());
EXPECT_TRUE(node2->current_frame_host()->IsRenderFrameLive());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, LoadEventForwarding) {
{
GURL main_url(
embedded_test_server()->GetURL("/frame_with_load_event.html"));
std::u16string expected_title(u"LOADED");
TitleWatcher title_watcher(shell()->web_contents(), expected_title);
EXPECT_TRUE(NavigateToURL(shell(), main_url));
EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title);
}
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
{
GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
std::u16string expected_title(u"LOADEDLOADED");
TitleWatcher title_watcher(shell()->web_contents(), expected_title);
TestNavigationObserver observer(shell()->web_contents());
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), foo_url));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(foo_url, observer.last_navigation_url());
EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title);
}
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, SubframePostMessage) {
GURL main_url(embedded_test_server()->GetURL(
"/frame_tree/page_with_post_message_frames.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
ASSERT_EQ(2U, root->child_count());
GURL same_site_url(embedded_test_server()->GetURL("/post_message.html"));
EXPECT_EQ(same_site_url, root->child_at(0)->current_url());
GURL foo_url(embedded_test_server()->GetURL("foo.com", "/post_message.html"));
EXPECT_EQ(foo_url, root->child_at(1)->current_url());
EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
root->child_at(1)->current_frame_host()->GetSiteInstance());
PostMessageAndWaitForReply(root->child_at(0),
"postToSibling('subframe-msg','subframe2')",
"\"done-subframe1\"");
std::u16string expected_title(u"subframe-msg");
TitleWatcher title_watcher(shell()->web_contents(), expected_title);
PostMessageAndWaitForReply(root->child_at(1), "postToParent('subframe-msg')",
"\"done-subframe2\"");
EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
EXPECT_EQ(1, GetReceivedMessages(root->child_at(0)));
EXPECT_EQ(2, GetReceivedMessages(root->child_at(1)));
EXPECT_EQ(1, GetReceivedMessages(root));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
PostMessageWithSubframeOnOpenerChain) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/frame_tree/page_with_post_message_frames.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
ASSERT_EQ(2U, root->child_count());
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site A ------- proxies for B\n"
" +--Site B ------- proxies for A\n"
"Where A = http://a.com/\n"
" B = http://foo.com/",
DepictFrameTree(root));
ShellAddedObserver new_shell_observer;
EXPECT_TRUE(ExecJs(root->child_at(0), "openPopup('about:blank');"));
Shell* popup = new_shell_observer.GetShell();
GURL popup_url(
embedded_test_server()->GetURL("bar.com", "/post_message.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(popup, popup_url));
ShellAddedObserver new_shell_observer2;
EXPECT_TRUE(ExecJs(popup, "openPopup('about:blank');"));
Shell* popup2 = new_shell_observer2.GetShell();
GURL popup2_url(
embedded_test_server()->GetURL("baz.com", "/post_message.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(popup2, popup2_url));
EXPECT_EQ(
" Site A ------------ proxies for B C D\n"
" |--Site A ------- proxies for B C D\n"
" +--Site B ------- proxies for A C D\n"
"Where A = http://a.com/\n"
" B = http://foo.com/\n"
" C = http://bar.com/\n"
" D = http://baz.com/",
DepictFrameTree(root));
FrameTreeNode* popup_root =
static_cast<WebContentsImpl*>(popup->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(
" Site C ------------ proxies for A D\n"
"Where A = http://a.com/\n"
" C = http://bar.com/\n"
" D = http://baz.com/",
DepictFrameTree(popup_root));
PostMessageAndWaitForReply(root->child_at(0), "postToPopup('subframe-msg')",
"\"done-subframe1\"");
EXPECT_TRUE(ExecJs(popup, "window.name = 'popup';"));
PostMessageAndWaitForReply(popup_root, "postToOpener('subframe-msg', '*')",
"\"done-popup\"");
FrameTreeNode* popup2_root =
static_cast<WebContentsImpl*>(popup2->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_TRUE(ExecJs(popup2, "window.name = 'popup2';"));
PostMessageAndWaitForReply(popup2_root,
"postToOpenerOfOpener('subframe-msg', '*')",
"\"done-popup2\"");
EXPECT_EQ(0, GetReceivedMessages(root));
EXPECT_EQ(3, GetReceivedMessages(root->child_at(0)));
EXPECT_EQ(0, GetReceivedMessages(root->child_at(1)));
EXPECT_EQ(2, GetReceivedMessages(popup_root));
EXPECT_EQ(1, GetReceivedMessages(popup2_root));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, IndexedFrameAccess) {
GURL main_url(
embedded_test_server()->GetURL("a.com", "/frame_tree/top.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
ASSERT_EQ(3U, root->child_count());
FrameTreeNode* child0 = root->child_at(0);
FrameTreeNode* child1 = root->child_at(1);
FrameTreeNode* child2 = root->child_at(2);
GURL b_url(embedded_test_server()->GetURL("b.com", "/post_message.html"));
GURL c_url(embedded_test_server()->GetURL("c.com", "/post_message.html"));
GURL d_url(embedded_test_server()->GetURL("d.com", "/post_message.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(child0, b_url));
EXPECT_TRUE(NavigateToURLFromRenderer(child1, c_url));
EXPECT_TRUE(NavigateToURLFromRenderer(child2, d_url));
EXPECT_EQ(
" Site A ------------ proxies for B C D\n"
" |--Site B ------- proxies for A C D\n"
" |--Site C ------- proxies for A B D\n"
" +--Site D ------- proxies for A B C\n"
"Where A = http://a.com/\n"
" B = http://b.com/\n"
" C = http://c.com/\n"
" D = http://d.com/",
DepictFrameTree(root));
EXPECT_EQ(true, EvalJs(child0, "window === parent.frames[0];"));
EXPECT_EQ(true, EvalJs(child1, "window === parent.frames[1];"));
EXPECT_EQ(true, EvalJs(child2, "window === parent.frames[2];"));
PostMessageAndWaitForReply(child0, "postToSibling('subframe-msg', 1)",
"\"done-1-1-name\"");
PostMessageAndWaitForReply(child1, "postToSibling('subframe-msg', 2)",
"\"done-1-2-name\"");
EXPECT_EQ(1, GetReceivedMessages(child0));
EXPECT_EQ(2, GetReceivedMessages(child1));
EXPECT_EQ(1, GetReceivedMessages(child2));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, RFPHDestruction) {
GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
TestNavigationObserver observer(shell()->web_contents());
FrameTreeNode* child = root->child_at(0);
GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
{
RenderFrameDeletedObserver deleted_observer(child->current_frame_host());
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), url));
deleted_observer.WaitUntilDeleted();
}
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(url, observer.last_navigation_url());
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site B ------- proxies for A\n"
" +--Site A ------- proxies for B\n"
" |--Site A -- proxies for B\n"
" +--Site A -- proxies for B\n"
" +--Site A -- proxies for B\n"
"Where A = http://127.0.0.1/\n"
" B = http://foo.com/",
DepictFrameTree(root));
url = embedded_test_server()->GetURL("bar.com", "/title3.html");
{
RenderFrameDeletedObserver deleted_observer(child->current_frame_host());
NavigateIframeToURL(shell()->web_contents(), "test", url);
deleted_observer.WaitUntilDeleted();
}
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(url, observer.last_navigation_url());
EXPECT_EQ(
" Site A ------------ proxies for C\n"
" |--Site C ------- proxies for A\n"
" +--Site A ------- proxies for C\n"
" |--Site A -- proxies for C\n"
" +--Site A -- proxies for C\n"
" +--Site A -- proxies for C\n"
"Where A = http://127.0.0.1/\n"
" C = http://bar.com/",
DepictFrameTree(root));
{
RenderFrameDeletedObserver deleted_observer(child->current_frame_host());
url = embedded_test_server()->GetURL("/title1.html");
EXPECT_TRUE(NavigateToURLFromRenderer(child, url));
deleted_observer.WaitUntilDeleted();
}
EXPECT_EQ(url, observer.last_navigation_url());
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(
" Site A\n"
" |--Site A\n"
" +--Site A\n"
" |--Site A\n"
" +--Site A\n"
" +--Site A\n"
"Where A = http://127.0.0.1/",
DepictFrameTree(root));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, OpenPopupWithRemoteParent) {
GURL main_url(
embedded_test_server()->GetURL("a.com", "/site_per_process_main.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url));
Shell* new_shell =
OpenPopup(root->child_at(0), GURL(url::kAboutBlankURL), "");
EXPECT_TRUE(new_shell);
FrameTreeNode* popup_root =
static_cast<WebContentsImpl*>(new_shell->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(root->child_at(0), popup_root->opener());
EXPECT_EQ(frame_url.spec(),
EvalJs(popup_root, "window.opener.location.href;"));
GURL popup_url(embedded_test_server()->GetURL("c.com", "/title2.html"));
Shell* cross_site_popup = OpenPopup(root->child_at(0), popup_url, "");
EXPECT_TRUE(cross_site_popup);
FrameTreeNode* cross_site_popup_root =
static_cast<WebContentsImpl*>(cross_site_popup->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(cross_site_popup_root->current_url(), popup_url);
EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
cross_site_popup->web_contents()->GetSiteInstance());
EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
cross_site_popup->web_contents()->GetSiteInstance());
EXPECT_EQ(root->child_at(0), cross_site_popup_root->opener());
EXPECT_EQ(true, EvalJs(cross_site_popup_root,
"window.opener === window.opener.top.frames[0];"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, NavigatePopupToIllegalURL) {
GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
GURL popup_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
Shell* popup = OpenPopup(shell(), popup_url, "foo");
EXPECT_TRUE(popup);
EXPECT_NE(popup->web_contents()->GetSiteInstance(),
shell()->web_contents()->GetSiteInstance());
WebContentsConsoleObserver console_observer(web_contents());
console_observer.SetPattern("Not allowed to load local resource:*");
GURL file_url("file:///");
NavigateNamedFrame(shell(), file_url, "foo");
EXPECT_TRUE(WaitForLoadStop(popup->web_contents()));
EXPECT_EQ(popup_url, popup->web_contents()->GetLastCommittedURL());
EXPECT_TRUE(base::MatchPattern(console_observer.GetMessageAt(0u),
"Not allowed to load local resource: file:*"));
GURL chrome_url(std::string(kChromeUIScheme) + "://" +
std::string(kChromeUIGpuHost));
NavigateNamedFrame(shell(), chrome_url, "foo");
EXPECT_TRUE(WaitForLoadStop(popup->web_contents()));
EXPECT_EQ(popup_url, popup->web_contents()->GetLastCommittedURL());
EXPECT_TRUE(
base::MatchPattern(console_observer.GetMessageAt(1u),
std::string("Not allowed to load local resource: ") +
kChromeUIScheme + ":*"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
DiscoverNamedFrameFromAncestorOfOpener) {
GURL main_url(
embedded_test_server()->GetURL("a.com", "/site_per_process_main.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url));
Shell* foo_shell =
OpenPopup(root->child_at(0), GURL(url::kAboutBlankURL), "foo");
EXPECT_TRUE(foo_shell);
FrameTreeNode* foo_root =
static_cast<WebContentsImpl*>(foo_shell->web_contents())
->GetPrimaryFrameTree()
.root();
SiteInstanceImpl* site_instance_a =
root->current_frame_host()->GetSiteInstance();
RenderFrameProxyHost* popup_rfph_for_a =
foo_root->current_frame_host()
->browsing_context_state()
->GetRenderFrameProxyHost(site_instance_a->group());
EXPECT_TRUE(popup_rfph_for_a);
GURL named_frame_url(embedded_test_server()->GetURL("c.com", "/title2.html"));
NavigateNamedFrame(shell(), named_frame_url, "foo");
EXPECT_TRUE(WaitForLoadStop(foo_shell->web_contents()));
EXPECT_EQ(named_frame_url, foo_root->current_url());
GURL d_url(embedded_test_server()->GetURL("d.com", "/title3.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(foo_shell, d_url));
EXPECT_EQ(d_url, foo_root->current_url());
NavigateNamedFrame(shell(), named_frame_url, "foo");
EXPECT_TRUE(WaitForLoadStop(foo_shell->web_contents()));
EXPECT_EQ(named_frame_url, foo_root->current_url());
}
class SitePerProcessFencedFrameTest : public SitePerProcessBrowserTestBase {
public:
SitePerProcessFencedFrameTest() {
fenced_frame_helper_ =
std::make_unique<content::test::FencedFrameTestHelper>();
}
void SetUpOnMainThread() override {
SitePerProcessBrowserTestBase::SetUpOnMainThread();
https_server_.ServeFilesFromSourceDirectory(GetTestDataFilePath());
ASSERT_TRUE(https_server_.Start());
}
protected:
net::EmbeddedTestServer& https_server() { return https_server_; }
content::RenderFrameHost* CreateFencedFrame(content::RenderFrameHost* parent,
const GURL& url) {
if (fenced_frame_helper_) {
return fenced_frame_helper_->CreateFencedFrame(parent, url);
}
content::TestNavigationManager navigation(web_contents(), url);
constexpr char kAddFencedFrameScript[] = R"({
const fenced_frame = document.createElement('fencedframe');
fenced_frame.src = $1;
document.body.appendChild(fenced_frame);
})";
EXPECT_TRUE(ExecJs(parent, content::JsReplace(kAddFencedFrameScript, url)));
EXPECT_TRUE(navigation.WaitForNavigationFinished());
return ChildFrameAt(parent, 0);
}
private:
base::test::ScopedFeatureList feature_list_;
std::unique_ptr<content::test::FencedFrameTestHelper> fenced_frame_helper_;
net::EmbeddedTestServer https_server_{net::EmbeddedTestServer::TYPE_HTTPS};
};
IN_PROC_BROWSER_TEST_F(SitePerProcessFencedFrameTest,
PopupFromFencedFrameDoesNotCreateProxy) {
GURL main_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
GURL fenced_frame_url(https_server().GetURL("/fenced_frames/title1.html"));
RenderFrameHost* fenced_frame_host = CreateFencedFrame(
web_contents()->GetPrimaryMainFrame(), fenced_frame_url);
EXPECT_NE(nullptr, fenced_frame_host);
Shell* popup_shell =
OpenPopup(fenced_frame_host, GURL(url::kAboutBlankURL), "foo", "", false);
EXPECT_TRUE(popup_shell);
FrameTreeNode* popup_root =
static_cast<WebContentsImpl*>(popup_shell->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(nullptr, popup_root->opener());
SiteInstanceImpl* site_instance =
root->current_frame_host()->GetSiteInstance();
EXPECT_FALSE(popup_root->current_frame_host()
->browsing_context_state()
->GetRenderFrameProxyHost(site_instance->group()));
SiteInstanceImpl* embedder_site_instance =
static_cast<RenderFrameHostImpl*>(fenced_frame_host)->GetSiteInstance();
EXPECT_FALSE(popup_root->current_frame_host()
->browsing_context_state()
->GetRenderFrameProxyHost(embedder_site_instance->group()));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
DiscoverFrameAfterSettingWindowName) {
GURL main_url(
embedded_test_server()->GetURL("a.com", "/site_per_process_main.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
GURL a_com_url(embedded_test_server()->GetURL("a.com", "/title3.html"));
Shell* a_com_shell = OpenPopup(root->child_at(0), a_com_url, "");
EXPECT_TRUE(a_com_shell);
GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url));
Shell* foo_shell =
OpenPopup(root->child_at(0), GURL(url::kAboutBlankURL), "");
EXPECT_TRUE(foo_shell);
FrameTreeNode* foo_root =
static_cast<WebContentsImpl*>(foo_shell->web_contents())
->GetPrimaryFrameTree()
.root();
SiteInstanceImpl* site_instance_a =
root->current_frame_host()->GetSiteInstance();
EXPECT_FALSE(foo_root->current_frame_host()
->browsing_context_state()
->GetRenderFrameProxyHost(site_instance_a->group()));
EXPECT_TRUE(ExecJs(foo_shell, "window.name = 'foo'"));
EXPECT_TRUE(foo_root->current_frame_host()
->browsing_context_state()
->GetRenderFrameProxyHost(site_instance_a->group()));
GURL named_frame_url(embedded_test_server()->GetURL("c.com", "/title2.html"));
NavigateNamedFrame(a_com_shell, named_frame_url, "foo");
EXPECT_TRUE(WaitForLoadStop(foo_shell->web_contents()));
EXPECT_EQ(named_frame_url, foo_root->current_url());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, UpdateSubframeOpener) {
GURL main_url = embedded_test_server()->GetURL(
"foo.com", "/frame_tree/page_with_two_frames.html");
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(2U, root->child_count());
Shell* popup_shell = OpenPopup(shell(), GURL(url::kAboutBlankURL), "popup");
EXPECT_TRUE(popup_shell);
GURL popup_url(embedded_test_server()->GetURL(
"bar.com", "/frame_tree/page_with_post_message_frames.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(popup_shell, popup_url));
FrameTreeNode* popup_root =
static_cast<WebContentsImpl*>(popup_shell->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(2U, popup_root->child_count());
EXPECT_EQ(root, popup_root->opener());
EXPECT_EQ(true, EvalJs(root->child_at(1), "!!window.open('','popup');"));
EXPECT_EQ(root->child_at(1), popup_root->opener());
EXPECT_EQ(true,
EvalJs(popup_shell,
"window.opener === window.opener.parent.frames['frame2'];"));
EXPECT_EQ(true, EvalJs(root->child_at(0), "!!window.open('','subframe2');"));
EXPECT_EQ(root->child_at(0), popup_root->child_at(1)->opener());
EXPECT_EQ(true,
EvalJs(popup_root->child_at(1),
"window.opener === window.opener.parent.frames['frame1'];"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
NavigatingSubframePreservesOpenerInParent) {
GURL main_url = embedded_test_server()->GetURL("a.com", "/post_message.html");
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
GURL popup_url(embedded_test_server()->GetURL(
"b.com", "/cross_site_iframe_factory.html?b(b)"));
Shell* popup_shell = OpenPopup(shell(), popup_url, "popup");
EXPECT_TRUE(popup_shell);
FrameTreeNode* popup_root =
static_cast<WebContentsImpl*>(popup_shell->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(1U, popup_root->child_count());
EXPECT_EQ(root, popup_root->opener());
GURL frame_url(embedded_test_server()->GetURL("c.com", "/post_message.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(popup_root->child_at(0), frame_url));
EXPECT_EQ(true, EvalJs(popup_root->child_at(0), "!!parent.opener;"));
std::u16string expected_title = u"msg";
TitleWatcher title_watcher(shell()->web_contents(), expected_title);
EXPECT_EQ(true, EvalJs(popup_root->child_at(0),
"postToOpenerOfParent('msg','*');"));
EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, NavigateSubframeWithOpener) {
GURL main_url(embedded_test_server()->GetURL(
"foo.com", "/frame_tree/page_with_two_frames.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site B ------- proxies for A\n"
" +--Site A ------- proxies for B\n"
"Where A = http://foo.com/\n"
" B = http://bar.com/",
DepictFrameTree(root));
EXPECT_EQ(true, EvalJs(root, "!!window.open('','frame1');"));
EXPECT_EQ(root, root->child_at(0)->opener());
EXPECT_EQ(true,
EvalJs(root->child_at(0), "window.opener === window.parent;"));
GURL frame_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url));
EXPECT_EQ(true,
EvalJs(root->child_at(0), "window.opener === window.parent;"));
GURL frame2_url(embedded_test_server()->GetURL("qux.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(1), frame2_url));
EXPECT_EQ(true, EvalJs(root->child_at(1),
"parent.frames['frame1'].opener === parent;"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
NewRenderFrameProxyPreservesOpener) {
GURL main_url(
embedded_test_server()->GetURL("foo.com", "/post_message.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
GURL popup_url(embedded_test_server()->GetURL(
"bar.com", "/frame_tree/page_with_post_message_frames.html"));
Shell* popup_shell = OpenPopup(shell(), popup_url, "popup");
EXPECT_TRUE(popup_shell);
FrameTreeNode* popup_root =
static_cast<WebContentsImpl*>(popup_shell->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site A ------- proxies for B\n"
" +--Site B ------- proxies for A\n"
"Where A = http://bar.com/\n"
" B = http://foo.com/",
DepictFrameTree(popup_root));
EXPECT_EQ(true, EvalJs(root, "!!window.open('','subframe2');"));
EXPECT_EQ(root, popup_root->child_at(1)->opener());
EXPECT_EQ(true,
EvalJs(popup_root->child_at(0),
"parent.frames['subframe2'].opener && "
" parent.frames['subframe2'].opener === parent.opener;"));
GURL frame_url(
embedded_test_server()->GetURL("baz.com", "/post_message.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(popup_root->child_at(0), frame_url));
EXPECT_EQ(true,
EvalJs(popup_root->child_at(0),
"parent.frames['subframe2'].opener && "
" parent.frames['subframe2'].opener === parent.opener;"));
std::u16string expected_title = u"msg";
TitleWatcher title_watcher(shell()->web_contents(), expected_title);
EXPECT_EQ(true, EvalJs(popup_root->child_at(0),
"postToOpenerOfSibling('subframe2', 'msg', '*');"));
EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
}
#if BUILDFLAG(IS_MAC)
#define MAYBE_RenderViewHostIsNotReusedAfterDelayedUnloadACK \
DISABLED_RenderViewHostIsNotReusedAfterDelayedUnloadACK
#else
#define MAYBE_RenderViewHostIsNotReusedAfterDelayedUnloadACK \
RenderViewHostIsNotReusedAfterDelayedUnloadACK
#endif
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
MAYBE_RenderViewHostIsNotReusedAfterDelayedUnloadACK) {
GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), a_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
RenderFrameHostImpl* rfh = root->current_frame_host();
RenderViewHostImpl* rvh = rfh->render_view_host();
int rvh_routing_id = rvh->GetRoutingID();
int rvh_process_id = rvh->GetProcess()->GetID();
SiteInstanceImpl* site_instance = rfh->GetSiteInstance();
RenderFrameDeletedObserver deleted_observer(rfh);
auto unload_ack_filter = base::BindRepeating([] { return true; });
rfh->SetUnloadACKCallbackForTesting(unload_ack_filter);
rfh->DisableUnloadTimerForTesting();
GURL b_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
TestFrameNavigationObserver commit_observer(root);
EXPECT_TRUE(ExecJs(shell(), JsReplace("location = $1", b_url)));
commit_observer.WaitForCommit();
EXPECT_FALSE(deleted_observer.deleted());
EXPECT_THAT(
rfh->lifecycle_state(),
testing::AnyOf(
testing::Eq(
RenderFrameHostImpl::LifecycleStateImpl::kRunningUnloadHandlers),
testing::Eq(
RenderFrameHostImpl::LifecycleStateImpl::kInBackForwardCache)));
content::RenderProcessHostWatcher crash_observer(
rvh->GetProcess(),
content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
EXPECT_TRUE(rvh->GetProcess()->Shutdown(0));
crash_observer.Wait();
EXPECT_FALSE(root->frame_tree().GetRenderViewHost(site_instance->group()));
EXPECT_TRUE(deleted_observer.deleted());
TestNavigationObserver navigation_observer(shell()->web_contents());
shell()->LoadURLForFrame(a_url, std::string(),
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK));
RenderFrameHostImpl* pending_rfh =
root->render_manager()->speculative_frame_host();
RenderViewHostImpl* pending_rvh = pending_rfh->render_view_host();
if (CanCrossSiteNavigationsProactivelySwapBrowsingInstances())
EXPECT_NE(site_instance, pending_rfh->GetSiteInstance());
else
EXPECT_EQ(site_instance, pending_rfh->GetSiteInstance());
EXPECT_FALSE(rvh_routing_id == pending_rvh->GetRoutingID() &&
rvh_process_id == pending_rvh->GetProcess()->GetID());
navigation_observer.Wait();
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
ReusePendingDeleteRenderViewHostForSubframe) {
GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
std::string script =
"window.onunload = function() { "
" var start = Date.now();"
" while (Date.now() - start < 1000);"
"}";
EXPECT_TRUE(ExecJs(shell(), script));
GURL second_url(embedded_test_server()->GetURL(
"b.com", "/cross_site_iframe_factory.html?b(a)"));
EXPECT_TRUE(NavigateToURL(shell(), second_url));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
CrossProcessFocusChangeFiresBlurEvents) {
GURL main_url(
embedded_test_server()->GetURL("a.com", "/page_with_input_field.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" +--Site B ------- proxies for A\n"
"Where A = http://a.com/\n"
" B = http://b.com/",
DepictFrameTree(root));
EXPECT_EQ("input-focus", EvalJs(shell(), "focusInputField()"));
EXPECT_EQ(root, root->frame_tree().GetFocusedFrame());
DOMMessageQueue msg_queue(web_contents());
SimulateMouseClick(
root->child_at(0)->current_frame_host()->GetRenderWidgetHost(), 1, 1);
EXPECT_EQ(true, EvalJs(shell(), "waitForBlur()"));
EXPECT_EQ(root->child_at(0), root->frame_tree().GetFocusedFrame());
SimulateMouseClick(shell()
->web_contents()
->GetPrimaryMainFrame()
->GetRenderViewHost()
->GetWidget(),
1, 1);
std::string status;
while (msg_queue.WaitForMessage(&status)) {
if (status == "\"document-blur\"")
break;
}
EXPECT_EQ(root, root->frame_tree().GetFocusedFrame());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, DocumentActiveElement) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b(c))"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(
" Site A ------------ proxies for B C\n"
" +--Site B ------- proxies for A C\n"
" +--Site C -- proxies for A B\n"
"Where A = http://a.com/\n"
" B = http://b.com/\n"
" C = http://c.com/",
DepictFrameTree(root));
FrameTreeNode* child = root->child_at(0);
FrameTreeNode* grandchild = root->child_at(0)->child_at(0);
EXPECT_EQ(root, root->frame_tree().GetFocusedFrame());
FocusFrame(child);
EXPECT_EQ(child, root->frame_tree().GetFocusedFrame());
auto verify_active_element_property = [](RenderFrameHost* rfh,
const std::string& property,
const std::string& expected_value) {
std::string script = base::StringPrintf(
"document.activeElement.%s.toLowerCase();", property.c_str());
EXPECT_EQ(expected_value, EvalJs(rfh, script));
};
RenderFrameHost* root_rfh = root->current_frame_host();
verify_active_element_property(root_rfh, "tagName", "iframe");
verify_active_element_property(root_rfh, "src", child->current_url().spec());
FocusFrame(root);
EXPECT_EQ(root, root->frame_tree().GetFocusedFrame());
verify_active_element_property(root_rfh, "tagName", "body");
FocusFrame(grandchild);
verify_active_element_property(root_rfh, "tagName", "iframe");
verify_active_element_property(root_rfh, "src", child->current_url().spec());
RenderFrameHost* child_rfh = child->current_frame_host();
verify_active_element_property(child_rfh, "tagName", "iframe");
verify_active_element_property(child_rfh, "src",
grandchild->current_url().spec());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, SubframeWindowFocus) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b,c)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(
" Site A ------------ proxies for B C\n"
" |--Site B ------- proxies for A C\n"
" +--Site C ------- proxies for A B\n"
"Where A = http://a.com/\n"
" B = http://b.com/\n"
" C = http://c.com/",
DepictFrameTree(root));
FrameTreeNode* child1 = root->child_at(0);
FrameTreeNode* child2 = root->child_at(1);
EXPECT_EQ(root, root->frame_tree().GetFocusedFrame());
const char kSetupFocusEvents[] = R"(
window.addEventListener('focus', function() {
window.top.postMessage('%s-got-focus', '*');
});
window.addEventListener('blur', function() {
window.top.postMessage('%s-lost-focus', '*');
});
function onEvent(target, eventName, property, value) {
return new Promise((resolve, reject) => {
function listener(event) {
if (event[property] == value) {
resolve();
target.removeEventListener(eventName, listener);
}
};
target.addEventListener(eventName, listener);
});
}
function expectMessages(messageList) {
var promiseList = messageList.map(
(dataValue) => onEvent(window, 'message', 'data', dataValue));
return Promise.all(promiseList);
}
)";
std::string script = base::StringPrintf(kSetupFocusEvents, "main", "main");
ExecuteScriptAsync(shell(), script);
script = base::StringPrintf(kSetupFocusEvents, "child1", "child1");
ExecuteScriptAsync(child1, script);
script = base::StringPrintf(kSetupFocusEvents, "child2", "child2");
ExecuteScriptAsync(child2, script);
EXPECT_EQ(true, EvalJs(root, R"((async function() {
allMessages = [];
window.addEventListener('message', (event) => {
allMessages.push(event.data);
});
var messages = expectMessages(['main-lost-focus', 'child1-got-focus']);
frames[0].focus();
await messages;
return allMessages.length == 2 || allMessages;
})())"));
EXPECT_EQ(child1, root->frame_tree().GetFocusedFrame());
EXPECT_EQ(true, EvalJs(root, R"((async function() {
var messages = expectMessages(['child1-lost-focus', 'child2-got-focus']);
frames[1].focus();
await messages;
return allMessages.length == 4 || allMessages;
})())"));
EXPECT_EQ(child2, root->frame_tree().GetFocusedFrame());
EXPECT_TRUE(
ExecJs(root,
"var messages = "
" expectMessages(['child2-lost-focus', 'main-got-focus']);"));
ExecuteScriptAsync(child2, "parent.focus()");
EXPECT_EQ(true, EvalJs(root, R"((async function() {
await messages;
return allMessages.length == 6 || allMessages;
})())"));
EXPECT_EQ(root, root->frame_tree().GetFocusedFrame());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
SubframeFocusNotLostWhenAnotherFrameNavigatesCrossSite) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a,a)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child1 = root->child_at(0);
FrameTreeNode* child2 = root->child_at(1);
EXPECT_EQ(root, root->frame_tree().GetFocusedFrame());
ExecuteScriptAsync(
child1, "document.body.appendChild(document.createElement('input'))");
FrameFocusedObserver focus_observer(child1->current_frame_host());
ExecuteScriptAsync(root, "frames[0].focus()");
focus_observer.Wait();
EXPECT_EQ(child1, root->frame_tree().GetFocusedFrame());
ExecuteScriptAsync(child1, "document.querySelector('input').focus()");
GURL b_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(child2, b_url));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(child1, root->frame_tree().GetFocusedFrame());
EXPECT_EQ(
"input",
base::ToLowerASCII(
EvalJs(child1, "document.activeElement.tagName").ExtractString()));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, OpenerSetLocation) {
GURL main_url(embedded_test_server()->GetURL("/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), main_url);
GURL cross_url = embedded_test_server()->GetURL("foo.com", "/title1.html");
Shell* popup = OpenPopup(shell(), cross_url, "");
EXPECT_EQ(popup->web_contents()->GetLastCommittedURL(), cross_url);
EXPECT_TRUE(
ExecJs(popup, JsReplace("window.opener.location.href = $1", cross_url)));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), cross_url);
}
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
#define MAYBE_NavigateProxyAndDetachBeforeProvisionalFrameCreation \
DISABLED_NavigateProxyAndDetachBeforeProvisionalFrameCreation
#else
#define MAYBE_NavigateProxyAndDetachBeforeProvisionalFrameCreation \
NavigateProxyAndDetachBeforeProvisionalFrameCreation
#endif
IN_PROC_BROWSER_TEST_P(
SitePerProcessBrowserTest,
MAYBE_NavigateProxyAndDetachBeforeProvisionalFrameCreation) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b,b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
WebContents* contents = shell()->web_contents();
FrameTreeNode* root =
static_cast<WebContentsImpl*>(contents)->GetPrimaryFrameTree().root();
EXPECT_EQ(2U, root->child_count());
FrameDeletedObserver observer(root->child_at(0)->current_frame_host());
std::string script =
"var f = document.querySelector('iframe');"
"f.contentWindow.location.href = 'about:blank';"
"setTimeout(function() { document.body.removeChild(f); }, 0);";
EXPECT_TRUE(ExecJs(root, script));
observer.Wait();
EXPECT_EQ(1U, root->child_count());
EXPECT_EQ(1, EvalJs(root, "frames.length"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
NavigateProxyAndDetachBeforeCommit) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b,b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
WebContents* contents = shell()->web_contents();
FrameTreeNode* root =
static_cast<WebContentsImpl*>(contents)->GetPrimaryFrameTree().root();
EXPECT_EQ(2U, root->child_count());
FrameTreeNode* child = root->child_at(0);
GURL same_site_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
NavigationController::LoadURLParams params(same_site_url);
params.transition_type = ui::PAGE_TRANSITION_LINK;
params.frame_tree_node_id = child->frame_tree_node_id();
child->navigator().controller().LoadURLWithParams(params);
FrameDeletedObserver observer(child->current_frame_host());
EXPECT_TRUE(ExecJs(
root, "document.body.removeChild(document.querySelector('iframe'));"));
observer.Wait();
EXPECT_EQ(1U, root->child_count());
EXPECT_EQ(1, EvalJs(root, "frames.length;"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, NavigateAboutBlankAndDetach) {
GURL main_url(
embedded_test_server()->GetURL("a.com", "/remove_frame_on_load.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
WebContents* contents = shell()->web_contents();
FrameTreeNode* root =
static_cast<WebContentsImpl*>(contents)->GetPrimaryFrameTree().root();
EXPECT_EQ(1U, root->child_count());
FrameTreeNode* child = root->child_at(0);
EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
child->current_frame_host()->GetSiteInstance());
FrameDeletedObserver observer(child->current_frame_host());
EXPECT_TRUE(
ExecJs(root, base::StringPrintf("f.src = '%s'", url::kAboutBlankURL)));
observer.Wait();
EXPECT_EQ(0, EvalJs(root, "frames.length;"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
SubframePendingAndBackToSameSiteInstance) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* node =
web_contents()->GetPrimaryFrameTree().root()->child_at(0);
EXPECT_TRUE(node);
EXPECT_NE(node->current_frame_host()->GetSiteInstance(),
node->parent()->GetSiteInstance());
GURL same_site_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
TestNavigationManager stalled_navigation(web_contents(), same_site_url);
{
NavigationController::LoadURLParams params(same_site_url);
params.transition_type = ui::PAGE_TRANSITION_LINK;
params.frame_tree_node_id = node->frame_tree_node_id();
node->navigator().controller().LoadURLWithParams(params);
EXPECT_TRUE(stalled_navigation.WaitForResponse());
}
RenderProcessHost* process =
node->render_manager()->speculative_frame_host()->GetProcess();
AgentSchedulingGroupHost* agent_scheduling_group =
AgentSchedulingGroupHost::GetOrCreate(*node->render_manager()
->speculative_frame_host()
->GetSiteInstance()
->group(),
*process);
RenderProcessHostWatcher watcher(
process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
int frame_routing_id =
node->render_manager()->speculative_frame_host()->GetRoutingID();
blink::LocalFrameToken frame_token =
node->render_manager()->speculative_frame_host()->GetFrameToken();
blink::RemoteFrameToken previous_frame_token =
node->render_manager()->GetProxyToParent()->GetFrameToken();
EXPECT_TRUE(NavigateToURLFromRenderer(
node, embedded_test_server()->GetURL("c.com", "/title2.html")));
{
mojo::PendingAssociatedRemote<mojom::Frame> pending_frame;
mojom::CreateFrameParamsPtr params = mojom::CreateFrameParams::New();
params->routing_id = frame_routing_id;
params->frame = pending_frame.InitWithNewEndpointAndPassReceiver();
std::ignore = params->interface_broker.InitWithNewPipeAndPassReceiver();
std::ignore = params->associated_interface_provider_remote
.InitWithNewEndpointAndPassReceiver();
params->previous_frame_token = previous_frame_token;
params->opener_frame_token = absl::nullopt;
params->parent_frame_token =
shell()->web_contents()->GetPrimaryMainFrame()->GetFrameToken();
params->frame_owner_properties = blink::mojom::FrameOwnerProperties::New();
params->frame_token = frame_token;
params->devtools_frame_token = base::UnguessableToken::Create();
params->document_token = blink::DocumentToken();
params->policy_container = CreateStubPolicyContainer();
params->replication_state = blink::mojom::FrameReplicationState::New();
agent_scheduling_group->CreateFrame(std::move(params));
}
DisableBackForwardCacheForTesting(web_contents(),
BackForwardCache::TEST_REQUIRES_NO_CACHING);
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL("d.com", "/title3.html")));
watcher.Wait();
EXPECT_TRUE(watcher.did_exit_normally());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, ParentDetachRemoteChild) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b,b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
WebContentsImpl* contents = web_contents();
EXPECT_EQ(2U, contents->GetPrimaryFrameTree().root()->child_count());
FrameTreeNode* node = contents->GetPrimaryFrameTree().root()->child_at(0);
EXPECT_TRUE(node);
EXPECT_NE(node->current_frame_host()->GetSiteInstance(),
node->parent()->GetSiteInstance());
RenderProcessHost* process = node->current_frame_host()->GetProcess();
AgentSchedulingGroupHost* agent_scheduling_group =
AgentSchedulingGroupHost::GetOrCreate(
*node->current_frame_host()->GetSiteInstance()->group(), *process);
RenderProcessHostWatcher watcher(
process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
int frame_routing_id = node->current_frame_host()->GetRoutingID();
blink::LocalFrameToken frame_token =
node->current_frame_host()->GetFrameToken();
int widget_routing_id =
node->current_frame_host()->GetRenderWidgetHost()->GetRoutingID();
absl::optional<blink::FrameToken> parent_frame_token =
node->parent()
->frame_tree_node()
->render_manager()
->GetFrameTokenForSiteInstanceGroup(
node->current_frame_host()->GetSiteInstance()->group());
EXPECT_TRUE(ExecJs(contents,
"document.body.removeChild("
"document.querySelectorAll('iframe')[0])"));
EXPECT_EQ(1U, contents->GetPrimaryFrameTree().root()->child_count());
{
mojo::PendingAssociatedRemote<mojom::Frame> pending_frame;
mojo::PendingAssociatedRemote<blink::mojom::FrameWidget> blink_frame_widget;
mojo::PendingAssociatedRemote<blink::mojom::Widget> blink_widget;
mojom::CreateFrameParamsPtr params = mojom::CreateFrameParams::New();
params->routing_id = frame_routing_id;
params->frame = pending_frame.InitWithNewEndpointAndPassReceiver();
std::ignore = params->interface_broker.InitWithNewPipeAndPassReceiver();
std::ignore = params->associated_interface_provider_remote
.InitWithNewEndpointAndPassReceiver();
params->previous_frame_token = absl::nullopt;
params->opener_frame_token = absl::nullopt;
params->parent_frame_token = parent_frame_token;
params->previous_sibling_frame_token = absl::nullopt;
params->frame_owner_properties = blink::mojom::FrameOwnerProperties::New();
params->widget_params = mojom::CreateFrameWidgetParams::New();
params->widget_params->routing_id = widget_routing_id;
params->widget_params->frame_widget =
blink_frame_widget.InitWithNewEndpointAndPassReceiver();
params->widget_params->widget =
blink_widget.InitWithNewEndpointAndPassReceiver();
std::ignore = params->widget_params->frame_widget_host
.InitWithNewEndpointAndPassReceiver();
std::ignore =
params->widget_params->widget_host.InitWithNewEndpointAndPassReceiver();
params->widget_params->visual_properties.screen_infos =
display::ScreenInfos(display::ScreenInfo());
params->replication_state = blink::mojom::FrameReplicationState::New();
params->replication_state->name = "name";
params->replication_state->unique_name = "name";
params->frame_token = frame_token;
params->devtools_frame_token = base::UnguessableToken::Create();
params->document_token = blink::DocumentToken();
params->policy_container = CreateStubPolicyContainer();
agent_scheduling_group->CreateFrame(std::move(params));
}
EXPECT_TRUE(NavigateToURLFromRenderer(
contents->GetPrimaryFrameTree().root()->child_at(0),
embedded_test_server()->GetURL("d.com", "/title3.html")));
watcher.Wait();
EXPECT_TRUE(watcher.did_exit_normally());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, SandboxFlagsInheritance) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_TRUE(ExecJs(
root, "document.querySelector('iframe').sandbox = 'allow-scripts';"));
network::mojom::WebSandboxFlags expected_flags =
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kAutomaticFeatures;
EXPECT_EQ(expected_flags,
root->child_at(0)->pending_frame_policy().sandbox_flags);
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
root->child_at(0)->effective_frame_policy().sandbox_flags);
GURL frame_url(embedded_test_server()->GetURL(
"b.com", "/cross_site_iframe_factory.html?b(c(d))"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url));
ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
FrameTreeNode* b_child = root->child_at(0);
FrameTreeNode* c_child = b_child->child_at(0);
FrameTreeNode* d_child = c_child->child_at(0);
EXPECT_EQ(expected_flags, b_child->effective_frame_policy().sandbox_flags);
EXPECT_EQ(expected_flags, c_child->effective_frame_policy().sandbox_flags);
EXPECT_EQ(expected_flags, d_child->effective_frame_policy().sandbox_flags);
EXPECT_EQ("null", GetOriginFromRenderer(b_child));
EXPECT_EQ("null", GetOriginFromRenderer(c_child));
EXPECT_EQ("null", GetOriginFromRenderer(d_child));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
SandboxFlagsNotInheritedBeforeNavigation) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_TRUE(ExecJs(
root, "document.querySelector('iframe').sandbox = 'allow-scripts';"));
network::mojom::WebSandboxFlags expected_flags =
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kAutomaticFeatures;
FrameTreeNode* child = root->child_at(0);
EXPECT_EQ(expected_flags, child->pending_frame_policy().sandbox_flags);
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
child->effective_frame_policy().sandbox_flags);
RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1);
EXPECT_TRUE(ExecJs(
child, "document.body.appendChild(document.createElement('iframe'));"));
frame_observer.Wait();
FrameTreeNode* grandchild = child->child_at(0);
GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
TestFrameNavigationObserver navigation_observer(grandchild);
EXPECT_TRUE(NavigateToURLFromRenderer(grandchild, frame_url));
navigation_observer.Wait();
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
grandchild->pending_frame_policy().sandbox_flags);
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
grandchild->effective_frame_policy().sandbox_flags);
EXPECT_EQ(GetExpectedOrigin("b.com"), GetOriginFromRenderer(grandchild));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
NewPopupInheritsSandboxFlagsFromOpener) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_TRUE(ExecJs(root,
"document.querySelector('iframe').sandbox = "
" 'allow-scripts allow-popups';"));
network::mojom::WebSandboxFlags expected_flags =
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kAutomaticFeatures &
~network::mojom::WebSandboxFlags::kPopups &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kTopNavigationToCustomProtocols;
EXPECT_EQ(expected_flags,
root->child_at(0)->pending_frame_policy().sandbox_flags);
GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
TestFrameNavigationObserver frame_observer(root->child_at(0));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url));
frame_observer.Wait();
EXPECT_EQ(expected_flags,
root->child_at(0)->effective_frame_policy().sandbox_flags);
EXPECT_EQ("null", GetOriginFromRenderer(root->child_at(0)));
const url::SchemeHostPort tuple_b(frame_url);
const url::Origin sandbox_origin_b = root->child_at(0)->current_origin();
EXPECT_TRUE(sandbox_origin_b.opaque());
EXPECT_EQ(tuple_b, sandbox_origin_b.GetTupleOrPrecursorTupleIfOpaque());
Shell* foo_shell =
OpenPopup(root->child_at(0), GURL(url::kAboutBlankURL), "foo");
EXPECT_TRUE(foo_shell);
FrameTreeNode* foo_root =
static_cast<WebContentsImpl*>(foo_shell->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(expected_flags, foo_root->effective_frame_policy().sandbox_flags);
EXPECT_EQ("null", GetOriginFromRenderer(foo_root));
url::Origin sandbox_origin_b2 = foo_root->current_origin();
EXPECT_NE(sandbox_origin_b2, sandbox_origin_b);
EXPECT_TRUE(sandbox_origin_b2.opaque());
EXPECT_EQ(tuple_b, sandbox_origin_b2.GetTupleOrPrecursorTupleIfOpaque());
GURL c_url(embedded_test_server()->GetURL("c.com", "/title1.html"));
const url::SchemeHostPort tuple_c(c_url);
{
TestFrameNavigationObserver popup_observer(foo_root);
EXPECT_TRUE(ExecJs(foo_root, JsReplace("location.href = $1", c_url)));
popup_observer.Wait();
EXPECT_EQ(c_url, foo_shell->web_contents()->GetLastCommittedURL());
}
EXPECT_EQ(expected_flags, foo_root->effective_frame_policy().sandbox_flags);
EXPECT_EQ("null", GetOriginFromRenderer(foo_root));
const url::Origin sandbox_origin_c = foo_root->current_origin();
EXPECT_NE(sandbox_origin_b, sandbox_origin_c);
EXPECT_TRUE(sandbox_origin_c.opaque());
EXPECT_EQ(tuple_c, sandbox_origin_c.GetTupleOrPrecursorTupleIfOpaque());
{
TestFrameNavigationObserver popup_observer(foo_root);
EXPECT_TRUE(ExecJs(foo_root, JsReplace("location.href = $1", frame_url)));
popup_observer.Wait();
EXPECT_EQ(frame_url, foo_shell->web_contents()->GetLastCommittedURL());
}
EXPECT_EQ(expected_flags, foo_root->effective_frame_policy().sandbox_flags);
EXPECT_EQ("null", GetOriginFromRenderer(foo_root));
url::Origin sandbox_origin_b3 = foo_root->current_origin();
EXPECT_TRUE(sandbox_origin_b3.opaque());
EXPECT_EQ(tuple_b, sandbox_origin_b3.GetTupleOrPrecursorTupleIfOpaque());
EXPECT_NE(sandbox_origin_b, sandbox_origin_b3);
EXPECT_NE(sandbox_origin_b2, sandbox_origin_b3);
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
OpenUnsandboxedPopupFromSandboxedFrame) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_TRUE(ExecJs(
root,
"document.querySelector('iframe').sandbox = "
" 'allow-scripts allow-popups allow-popups-to-escape-sandbox';"));
network::mojom::WebSandboxFlags expected_flags =
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kAutomaticFeatures &
~network::mojom::WebSandboxFlags::kPopups &
~network::mojom::WebSandboxFlags::kTopNavigationToCustomProtocols &
~network::mojom::WebSandboxFlags::kPropagatesToAuxiliaryBrowsingContexts;
EXPECT_EQ(expected_flags,
root->child_at(0)->pending_frame_policy().sandbox_flags);
GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
TestFrameNavigationObserver frame_observer(root->child_at(0));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url));
frame_observer.Wait();
EXPECT_EQ(expected_flags,
root->child_at(0)->effective_frame_policy().sandbox_flags);
GURL b_url(embedded_test_server()->GetURL("c.com", "/title1.html"));
Shell* foo_shell = OpenPopup(root->child_at(0), b_url, "foo");
EXPECT_TRUE(foo_shell);
FrameTreeNode* foo_root =
static_cast<WebContentsImpl*>(foo_shell->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
foo_root->effective_frame_policy().sandbox_flags);
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
foo_root->current_frame_host()->active_sandbox_flags());
EXPECT_EQ(url::Origin::Create(b_url).Serialize(),
EvalJs(foo_root, "self.origin;"));
}
IN_PROC_BROWSER_TEST_P(
SitePerProcessBrowserTest,
OpenSandboxedDocumentInUnsandboxedPopupFromSandboxedFrame) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_TRUE(ExecJs(
root,
"document.querySelector('iframe').sandbox = "
" 'allow-scripts allow-popups allow-popups-to-escape-sandbox';"));
network::mojom::WebSandboxFlags expected_flags =
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kAutomaticFeatures &
~network::mojom::WebSandboxFlags::kPopups &
~network::mojom::WebSandboxFlags::kTopNavigationToCustomProtocols &
~network::mojom::WebSandboxFlags::kPropagatesToAuxiliaryBrowsingContexts;
EXPECT_EQ(expected_flags,
root->child_at(0)->pending_frame_policy().sandbox_flags);
GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
TestFrameNavigationObserver frame_observer(root->child_at(0));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url));
frame_observer.Wait();
EXPECT_EQ(expected_flags,
root->child_at(0)->effective_frame_policy().sandbox_flags);
GURL foo_url("about:blank");
Shell* foo_shell = OpenPopup(root->child_at(0), foo_url, "foo");
EXPECT_TRUE(foo_shell);
FrameTreeNode* foo_root =
static_cast<WebContentsImpl*>(foo_shell->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
foo_root->effective_frame_policy().sandbox_flags);
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
foo_root->current_frame_host()->active_sandbox_flags());
}
IN_PROC_BROWSER_TEST_P(
SitePerProcessBrowserTest,
OpenSandboxedDocumentInUnsandboxedPopupFromCSPSandboxedDocument) {
GURL main_url = embedded_test_server()->GetURL(
"a.test",
"/set-header?"
"Content-Security-Policy: sandbox "
"allow-scripts allow-popups allow-popups-to-escape-sandbox");
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
network::mojom::WebSandboxFlags expected_flags =
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kAutomaticFeatures &
~network::mojom::WebSandboxFlags::kPopups &
~network::mojom::WebSandboxFlags::kTopNavigationToCustomProtocols &
~network::mojom::WebSandboxFlags::kPropagatesToAuxiliaryBrowsingContexts;
EXPECT_EQ(expected_flags, root->current_frame_host()->active_sandbox_flags());
GURL foo_url("about:blank");
Shell* foo_shell = OpenPopup(root, foo_url, "foo");
EXPECT_TRUE(foo_shell);
FrameTreeNode* foo_root =
static_cast<WebContentsImpl*>(foo_shell->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
foo_root->effective_frame_policy().sandbox_flags);
EXPECT_EQ(expected_flags,
foo_root->current_frame_host()->active_sandbox_flags());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessIgnoreCertErrorsBrowserTest,
DISABLED_SubresourceWithCertificateErrors) {
net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
https_server.ServeFilesFromSourceDirectory(GetTestDataFilePath());
SetupCrossSiteRedirector(&https_server);
ASSERT_TRUE(https_server.Start());
GURL url(https_server.GetURL(
"example.test",
"/mixed-content/non-redundant-cert-error-in-iframe.html"));
VisibleSecurityStateObserver displayed_content_with_cert_errors_observer(
shell()->web_contents(),
base::BindRepeating([](WebContents* web_contents) {
NavigationEntry* entry =
web_contents->GetController().GetLastCommittedEntry();
return entry && (entry->GetSSL().content_status &
SSLStatus::DISPLAYED_CONTENT_WITH_CERT_ERRORS) != 0;
}));
EXPECT_TRUE(NavigateToURL(shell(), url));
displayed_content_with_cert_errors_observer.Wait();
NavigationEntry* entry =
shell()->web_contents()->GetController().GetLastCommittedEntry();
ASSERT_TRUE(entry);
EXPECT_TRUE(net::IsCertStatusError(entry->GetSSL().cert_status));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, CrossSiteIframeDisplayNone) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
RenderWidgetHost* root_render_widget_host =
root->current_frame_host()->GetRenderWidgetHost();
EXPECT_TRUE(ExecJs(
shell(), "document.querySelector('iframe').style.display = 'none'"));
std::unique_ptr<MainThreadFrameObserver> observer(
new MainThreadFrameObserver(root_render_widget_host));
observer->Wait();
EXPECT_TRUE(ExecJs(shell(), "document.body.style.background = 'black'"));
observer->Wait();
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
CrossSiteIframeBlockedByXFrameOptionsOrCSP) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_TRUE(ExecJs(shell(),
"document.querySelector('iframe').onload = "
" function() { document.title = 'loaded'; };"));
GURL reported_blocked_url = embedded_test_server()->GetURL("b.com", "/");
const struct {
const char* url;
bool use_error_page;
std::string expected_console_message;
} kTestCases[] = {
{"/frame-ancestors-none.html", false,
"Refused to frame '" + reported_blocked_url.spec() +
"' because an ancestor violates the following Content Security "
"Policy directive: \"frame-ancestors 'none'\".\n"},
{"/x-frame-options-deny.html", true,
"Refused to display '" + reported_blocked_url.spec() +
"' in a frame because it set 'X-Frame-Options' to 'deny'."},
};
for (const auto& test : kTestCases) {
GURL blocked_url = embedded_test_server()->GetURL("b.com", test.url);
EXPECT_TRUE(ExecJs(shell(), "document.title = 'not loaded';"));
std::u16string expected_title(u"loaded");
TitleWatcher title_watcher(shell()->web_contents(), expected_title);
WebContentsConsoleObserver console_observer(shell()->web_contents());
console_observer.SetPattern("Refused to*");
TestNavigationObserver load_observer(shell()->web_contents());
EXPECT_TRUE(ExecJs(shell(),
JsReplace("frames[0].location.href = $1", blocked_url)));
load_observer.Wait();
const url::Origin child_origin =
root->child_at(0)->current_frame_host()->GetLastCommittedOrigin();
EXPECT_TRUE(child_origin.opaque());
EXPECT_EQ(url::Origin::Create(blocked_url.DeprecatedGetOriginAsURL())
.GetTupleOrPrecursorTupleIfOpaque(),
child_origin.GetTupleOrPrecursorTupleIfOpaque());
EXPECT_FALSE(load_observer.last_navigation_succeeded());
EXPECT_EQ(net::ERR_BLOCKED_BY_RESPONSE,
load_observer.last_net_error_code());
EXPECT_EQ(root->child_at(0)->current_frame_host()->GetLastCommittedURL(),
blocked_url);
EXPECT_EQ("Error", EvalJs(root->child_at(0), "document.title"));
EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
EXPECT_EQ(console_observer.GetMessageAt(0u), test.expected_console_message);
EXPECT_FALSE(root->child_at(0)->current_frame_host()->is_loading());
GURL c_url(embedded_test_server()->GetURL("c.com", "/title1.html"));
EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "child-0", c_url));
EXPECT_EQ(c_url, root->child_at(0)->current_url());
EXPECT_EQ(c_url.DeprecatedGetOriginAsURL().spec(),
root->child_at(0)->current_origin().Serialize() + "/");
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
root->child_at(0)->effective_frame_policy().sandbox_flags);
}
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
CrossSiteIframeBlockedByParentCSPFromHeaders) {
GURL main_url(
embedded_test_server()->GetURL("a.com", "/frame-src-self-and-b.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
GURL old_subframe_url(
embedded_test_server()->GetURL("b.com", "/title2.html"));
EXPECT_FALSE(root->child_at(0)->HasSameOrigin(*root));
EXPECT_EQ(old_subframe_url, root->child_at(0)->current_url());
const std::vector<network::mojom::ContentSecurityPolicyPtr>& root_csp =
root->current_frame_host()
->policy_container_host()
->policies()
.content_security_policies;
EXPECT_EQ(1u, root_csp.size());
EXPECT_EQ("frame-src 'self' http://b.com:*",
root_csp[0]->header->header_value);
EXPECT_TRUE(ExecJs(shell(),
"document.querySelector('iframe').onload = "
" function() { document.title = 'loaded'; };"));
EXPECT_TRUE(ExecJs(shell(), "document.title = 'not loaded';"));
std::u16string expected_title(u"loaded");
TitleWatcher title_watcher(shell()->web_contents(), expected_title);
TestNavigationObserver load_observer(shell()->web_contents());
GURL blocked_url = embedded_test_server()->GetURL("c.com", "/title3.html");
EXPECT_TRUE(ExecJs(root->child_at(0),
JsReplace("window.location.href = $1", blocked_url)));
EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
if (root->child_at(0)->current_frame_host()->is_loading())
load_observer.Wait();
EXPECT_NE(blocked_url,
root->child_at(0)->current_frame_host()->last_successful_url());
EXPECT_EQ(blocked_url, root->child_at(0)->current_url());
EXPECT_EQ("Error", EvalJs(root->child_at(0), "document.title"));
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
CrossSiteIframeBlockedByParentCSPFromMeta) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
GURL old_subframe_url(
embedded_test_server()->GetURL("b.com", "/title2.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), old_subframe_url));
EXPECT_TRUE(
ExecJs(shell(),
"var meta = document.createElement('meta');"
"meta.httpEquiv = 'Content-Security-Policy';"
"meta.content = 'frame-src https://a.com:*';"
"document.getElementsByTagName('head')[0].appendChild(meta);"));
EXPECT_FALSE(root->child_at(0)->HasSameOrigin(*root));
EXPECT_EQ(old_subframe_url, root->child_at(0)->current_url());
const std::vector<network::mojom::ContentSecurityPolicyPtr>& root_csp =
root->current_frame_host()
->policy_container_host()
->policies()
.content_security_policies;
EXPECT_EQ(1u, root_csp.size());
EXPECT_EQ("frame-src https://a.com:*", root_csp[0]->header->header_value);
EXPECT_TRUE(ExecJs(shell(),
"document.querySelector('iframe').onload = "
" function() { document.title = 'loaded'; };"));
EXPECT_TRUE(ExecJs(shell(), "document.title = 'not loaded';"));
std::u16string expected_title(u"loaded");
TitleWatcher title_watcher(shell()->web_contents(), expected_title);
TestNavigationObserver load_observer2(shell()->web_contents());
GURL blocked_url = embedded_test_server()->GetURL("c.com", "/title3.html");
EXPECT_TRUE(ExecJs(root->child_at(0),
JsReplace("window.location.href = $1;", blocked_url)));
EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
if (root->child_at(0)->current_frame_host()->is_loading())
load_observer2.Wait();
EXPECT_NE(blocked_url,
root->child_at(0)->current_frame_host()->last_successful_url());
EXPECT_EQ(blocked_url, root->child_at(0)->current_url());
EXPECT_EQ("Error", EvalJs(root->child_at(0), "document.title"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
CrossSiteIframeBlockedByCSPInheritedBySrcDocParent) {
GURL main_url(
embedded_test_server()->GetURL("a.com", "/frame-src-self-and-b.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* srcdoc_frame = root->child_at(1);
EXPECT_TRUE(srcdoc_frame != nullptr);
FrameTreeNode* navigating_frame = srcdoc_frame->child_at(0);
EXPECT_TRUE(navigating_frame != nullptr);
GURL old_subframe_url(
embedded_test_server()->GetURL("b.com", "/title2.html"));
EXPECT_TRUE(srcdoc_frame->HasSameOrigin(*root));
EXPECT_FALSE(srcdoc_frame->HasSameOrigin(*navigating_frame));
EXPECT_EQ(old_subframe_url, navigating_frame->current_url());
const std::vector<network::mojom::ContentSecurityPolicyPtr>& srcdoc_csp =
srcdoc_frame->current_frame_host()
->policy_container_host()
->policies()
.content_security_policies;
EXPECT_EQ(1u, srcdoc_csp.size());
EXPECT_EQ("frame-src 'self' http://b.com:*",
srcdoc_csp[0]->header->header_value);
EXPECT_TRUE(ExecJs(root,
"window.addEventListener('message', function(event) {"
" document.title = event.data;"
"});"));
EXPECT_TRUE(
ExecJs(srcdoc_frame,
"document.querySelector('iframe').onload = "
" function() { window.top.postMessage('loaded', '*'); };"));
EXPECT_TRUE(ExecJs(shell(), "document.title = 'not loaded';"));
std::u16string expected_title(u"loaded");
TitleWatcher title_watcher(shell()->web_contents(), expected_title);
TestNavigationObserver load_observer2(shell()->web_contents());
GURL blocked_url = embedded_test_server()->GetURL("c.com", "/title3.html");
EXPECT_TRUE(ExecJs(navigating_frame,
JsReplace("window.location.href = $1;", blocked_url)));
EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
if (navigating_frame->current_frame_host()->is_loading())
load_observer2.Wait();
EXPECT_NE(blocked_url,
navigating_frame->current_frame_host()->last_successful_url());
EXPECT_EQ(blocked_url, navigating_frame->current_url());
EXPECT_EQ("Error", EvalJs(navigating_frame, "document.title"));
EXPECT_TRUE(NavigateToURLFromRenderer(
srcdoc_frame, embedded_test_server()->GetURL("a.com", "/title1.html")));
EXPECT_EQ(0u, srcdoc_frame->current_frame_host()
->policy_container_host()
->policies()
.content_security_policies.size());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
NavigateMainFrameToChildSite) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
WebContentsImpl* contents = web_contents();
FrameTreeNode* root = contents->GetPrimaryFrameTree().root();
EXPECT_EQ(1U, root->child_count());
if (CanCrossSiteNavigationsProactivelySwapBrowsingInstances()) {
GURL popup_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(OpenPopup(root, popup_url, "foo"));
}
RenderViewHostImpl* rvh = contents->GetPrimaryFrameTree()
.GetRenderViewHost(root->child_at(0)
->current_frame_host()
->GetSiteInstance()
->group())
.get();
EXPECT_FALSE(rvh->is_active());
GURL b_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
auto script = JsReplace("parent.location = $1", b_url);
SimulateMouseClick(
root->child_at(0)->current_frame_host()->GetRenderWidgetHost(), 1, 1);
TestFrameNavigationObserver frame_observer(root);
EXPECT_TRUE(ExecJs(root->child_at(0), script));
frame_observer.Wait();
EXPECT_EQ(b_url, root->current_url());
EXPECT_EQ(rvh, contents->GetPrimaryFrameTree().GetRenderViewHost(
root->current_frame_host()->GetSiteInstance()->group()));
EXPECT_TRUE(rvh->is_active());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
CloseSubframeWidgetAndViewOnProcessExit) {
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();
root->child_at(0)
->current_frame_host()
->GetRenderWidgetHost()
->GetFrameWidgetInputHandler()
->SelectAll();
RenderProcessHost* subframe_process =
root->child_at(0)->current_frame_host()->GetProcess();
subframe_process->IncrementKeepAliveRefCount(0);
EXPECT_TRUE(NavigateToURLFromRenderer(
root->child_at(0),
embedded_test_server()->GetURL("a.com", "/title1.html")));
RenderProcessHostWatcher process_shutdown_observer(
subframe_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
subframe_process->DecrementKeepAliveRefCount(0);
process_shutdown_observer.Wait();
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
UserInteractionForChildFrameTest) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
UserInteractionObserver observer(web_contents());
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
SimulateMouseClick(
root->child_at(0)->current_frame_host()->GetRenderWidgetHost(), 5, 5);
EXPECT_TRUE(observer.WasUserInteractionReceived());
observer.Reset();
SimulateMouseClick(root->current_frame_host()->GetRenderWidgetHost(), 1, 1);
EXPECT_TRUE(observer.WasUserInteractionReceived());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
NavigateSubframeToDataUrlInSessionHistory) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b,b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(2U, root->child_count());
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site B ------- proxies for A\n"
" +--Site B ------- proxies for A\n"
"Where A = http://a.com/\n"
" B = http://b.com/",
DepictFrameTree(root));
TestNavigationObserver observer(shell()->web_contents());
FrameTreeNode* child = root->child_at(0);
GURL data_url("data:text/html,dataurl");
EXPECT_TRUE(NavigateToURLFromRenderer(child, data_url));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(data_url, observer.last_navigation_url());
scoped_refptr<SiteInstanceImpl> orig_site_instance =
child->current_frame_host()->GetSiteInstance();
EXPECT_NE(root->current_frame_host()->GetSiteInstance(), orig_site_instance);
GURL cross_site_url(embedded_test_server()->GetURL("c.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(child, cross_site_url));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(cross_site_url, observer.last_navigation_url());
EXPECT_EQ(3, web_contents()->GetController().GetEntryCount());
EXPECT_NE(orig_site_instance, child->current_frame_host()->GetSiteInstance());
EXPECT_TRUE(web_contents()->GetController().CanGoBack());
TestFrameNavigationObserver frame_observer(child);
web_contents()->GetController().GoBack();
frame_observer.WaitForCommit();
EXPECT_EQ(orig_site_instance, child->current_frame_host()->GetSiteInstance());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
SubframeDataUrlsAfterRestore) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/frame_tree/page_with_two_iframes.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(2U, root->child_count());
EXPECT_EQ(
" Site A ------------ proxies for B C\n"
" |--Site B ------- proxies for A C\n"
" +--Site C ------- proxies for A B\n"
"Where A = http://a.com/\n"
" B = http://bar.com/\n"
" C = http://baz.com/",
DepictFrameTree(root));
FrameTreeNode* child_0 = root->child_at(0);
FrameTreeNode* child_1 = root->child_at(1);
scoped_refptr<SiteInstanceImpl> child_site_instance_0 =
child_0->current_frame_host()->GetSiteInstance();
scoped_refptr<SiteInstanceImpl> child_site_instance_1 =
child_1->current_frame_host()->GetSiteInstance();
TestNavigationObserver observer(shell()->web_contents());
GURL data_url_0("data:text/html,dataurl_0");
{
TestFrameNavigationObserver commit_observer(child_0);
EXPECT_TRUE(ExecJs(child_0, JsReplace("location.href = $1", data_url_0)));
commit_observer.WaitForCommit();
}
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(data_url_0, observer.last_navigation_url());
EXPECT_EQ(child_site_instance_0,
child_0->current_frame_host()->GetSiteInstance());
GURL data_url_1("data:text/html,dataurl_1");
{
TestFrameNavigationObserver commit_observer(child_1);
EXPECT_TRUE(ExecJs(child_1, JsReplace("location.href = $1", data_url_1)));
commit_observer.WaitForCommit();
}
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(data_url_1, observer.last_navigation_url());
EXPECT_EQ(child_site_instance_1,
child_1->current_frame_host()->GetSiteInstance());
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
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 ));
EXPECT_EQ(0U, restored_entry->root_node()->children.size());
std::unique_ptr<NavigationEntryRestoreContextImpl> context =
std::make_unique<NavigationEntryRestoreContextImpl>();
restored_entry->SetPageState(entry->GetPageState(), context.get());
ASSERT_EQ(2U, restored_entry->root_node()->children.size());
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(2U, new_root->child_count());
EXPECT_EQ(main_url, new_root->current_url());
EXPECT_EQ("data", new_root->child_at(0)->current_url().scheme());
EXPECT_EQ("data", new_root->child_at(1)->current_url().scheme());
EXPECT_NE(new_root->current_frame_host()->GetSiteInstance(),
new_root->child_at(0)->current_frame_host()->GetSiteInstance());
EXPECT_NE(new_root->current_frame_host()->GetSiteInstance(),
new_root->child_at(1)->current_frame_host()->GetSiteInstance());
EXPECT_NE(new_root->child_at(0)->current_frame_host()->GetSiteInstance(),
new_root->child_at(1)->current_frame_host()->GetSiteInstance());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
SubframeBlankUrlsAfterRestore) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/frame_tree/page_with_two_iframes.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(2U, root->child_count());
EXPECT_EQ(
" Site A ------------ proxies for B C\n"
" |--Site B ------- proxies for A C\n"
" +--Site C ------- proxies for A B\n"
"Where A = http://a.com/\n"
" B = http://bar.com/\n"
" C = http://baz.com/",
DepictFrameTree(root));
FrameTreeNode* child_0 = root->child_at(0);
FrameTreeNode* child_1 = root->child_at(1);
scoped_refptr<SiteInstanceImpl> child_site_instance_0 =
child_0->current_frame_host()->GetSiteInstance();
scoped_refptr<SiteInstanceImpl> child_site_instance_1 =
child_1->current_frame_host()->GetSiteInstance();
TestNavigationObserver observer(shell()->web_contents());
GURL blank_url("about:blank");
{
TestFrameNavigationObserver commit_observer(child_0);
EXPECT_TRUE(ExecJs(child_0, JsReplace("location.href = $1", blank_url)));
commit_observer.WaitForCommit();
}
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(blank_url, observer.last_navigation_url());
EXPECT_EQ(child_site_instance_0,
child_0->current_frame_host()->GetSiteInstance());
GURL blank_url_ref("about:blank#1");
{
TestFrameNavigationObserver commit_observer(child_1);
EXPECT_TRUE(
ExecJs(child_1, JsReplace("location.href = $1", blank_url_ref)));
commit_observer.WaitForCommit();
}
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(blank_url_ref, observer.last_navigation_url());
EXPECT_EQ(child_site_instance_1,
child_1->current_frame_host()->GetSiteInstance());
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
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 ));
EXPECT_EQ(0U, restored_entry->root_node()->children.size());
std::unique_ptr<NavigationEntryRestoreContextImpl> context =
std::make_unique<NavigationEntryRestoreContextImpl>();
restored_entry->SetPageState(entry->GetPageState(), context.get());
ASSERT_EQ(2U, restored_entry->root_node()->children.size());
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(2U, new_root->child_count());
EXPECT_EQ(main_url, new_root->current_url());
auto* new_child_0 = new_root->child_at(0);
auto* new_child_1 = new_root->child_at(1);
EXPECT_TRUE(new_child_0->current_url().IsAboutBlank());
EXPECT_TRUE(new_child_1->current_url().IsAboutBlank());
EXPECT_EQ(new_root->current_frame_host()->GetLastCommittedOrigin(),
root->current_frame_host()->GetLastCommittedOrigin());
EXPECT_EQ(new_child_0->current_frame_host()
->GetLastCommittedOrigin()
.GetTupleOrPrecursorTupleIfOpaque(),
child_0->current_frame_host()
->GetLastCommittedOrigin()
.GetTupleOrPrecursorTupleIfOpaque());
EXPECT_EQ(new_child_1->current_frame_host()
->GetLastCommittedOrigin()
.GetTupleOrPrecursorTupleIfOpaque(),
child_1->current_frame_host()
->GetLastCommittedOrigin()
.GetTupleOrPrecursorTupleIfOpaque());
EXPECT_NE(child_0->current_frame_host()
->GetLastCommittedOrigin()
.GetTupleOrPrecursorTupleIfOpaque(),
child_1->current_frame_host()
->GetLastCommittedOrigin()
.GetTupleOrPrecursorTupleIfOpaque());
EXPECT_EQ(
new_root->current_frame_host()->GetLastCommittedOrigin().Serialize(),
GetOriginFromRenderer(new_root));
EXPECT_EQ(GetExpectedOrigin("bar.com"), GetOriginFromRenderer(new_child_0));
EXPECT_EQ(GetExpectedOrigin("baz.com"), GetOriginFromRenderer(new_child_1));
EXPECT_NE(new_root->current_frame_host()->GetSiteInstance(),
new_child_0->current_frame_host()->GetSiteInstance());
EXPECT_NE(new_root->current_frame_host()->GetSiteInstance(),
new_child_1->current_frame_host()->GetSiteInstance());
EXPECT_NE(new_child_0->current_frame_host()->GetSiteInstance(),
new_child_1->current_frame_host()->GetSiteInstance());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
SubframeSrcdocUrlAfterRestore) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/frame_tree/page_with_srcdoc_frame.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(1U, root->child_count());
FrameTreeNode* child = root->child_at(0);
scoped_refptr<SiteInstanceImpl> child_site_instance =
child->current_frame_host()->GetSiteInstance();
EXPECT_EQ(child_site_instance, root->current_frame_host()->GetSiteInstance());
NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
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 ));
EXPECT_EQ(0U, restored_entry->root_node()->children.size());
std::unique_ptr<NavigationEntryRestoreContextImpl> context =
std::make_unique<NavigationEntryRestoreContextImpl>();
restored_entry->SetPageState(entry->GetPageState(), context.get());
ASSERT_EQ(1U, restored_entry->root_node()->children.size());
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, new_root->current_url());
EXPECT_TRUE(new_root->child_at(0)->current_url().IsAboutSrcdoc());
if (blink::features::IsNewBaseUrlInheritanceBehaviorEnabled()) {
EXPECT_EQ(
main_url,
GURL(
EvalJs(new_root->child_at(0), "document.baseURI").ExtractString()));
}
EXPECT_EQ(new_root->current_frame_host()->GetSiteInstance(),
new_root->child_at(0)->current_frame_host()->GetSiteInstance());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
NavigateSubframeToAboutBlankInSessionHistory) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b,b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(2U, root->child_count());
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" |--Site B ------- proxies for A\n"
" +--Site B ------- proxies for A\n"
"Where A = http://a.com/\n"
" B = http://b.com/",
DepictFrameTree(root));
TestNavigationObserver observer(shell()->web_contents());
FrameTreeNode* child = root->child_at(0);
GURL about_blank_url("about:blank");
EXPECT_TRUE(NavigateToURLFromRenderer(child, about_blank_url));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(about_blank_url, observer.last_navigation_url());
scoped_refptr<SiteInstanceImpl> orig_site_instance =
child->current_frame_host()->GetSiteInstance();
EXPECT_NE(root->current_frame_host()->GetSiteInstance(), orig_site_instance);
GURL cross_site_url(embedded_test_server()->GetURL("c.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(child, cross_site_url));
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(cross_site_url, observer.last_navigation_url());
EXPECT_EQ(3, web_contents()->GetController().GetEntryCount());
EXPECT_NE(orig_site_instance, child->current_frame_host()->GetSiteInstance());
EXPECT_TRUE(web_contents()->GetController().CanGoBack());
TestFrameNavigationObserver frame_observer(child);
web_contents()->GetController().GoBack();
frame_observer.WaitForCommit();
EXPECT_EQ(orig_site_instance, child->current_frame_host()->GetSiteInstance());
}
class ShowCreatedWindowInterceptor
: public blink::mojom::LocalMainFrameHostInterceptorForTesting {
public:
ShowCreatedWindowInterceptor(
RenderFrameHostImpl* render_frame_host,
base::OnceCallback<void(int32_t pending_widget_routing_id)> test_callback)
: render_frame_host_(render_frame_host),
test_callback_(std::move(test_callback)),
swapped_impl_(
render_frame_host_->local_main_frame_host_receiver_for_testing(),
this) {}
~ShowCreatedWindowInterceptor() override = default;
blink::mojom::LocalMainFrameHost* GetForwardingInterface() override {
return render_frame_host_;
}
void ShowCreatedWindow(const blink::LocalFrameToken& opener_frame_token,
WindowOpenDisposition disposition,
blink::mojom::WindowFeaturesPtr window_features,
bool user_gesture,
ShowCreatedWindowCallback callback) override {
show_callback_ = std::move(callback);
opener_frame_token_ = opener_frame_token;
user_gesture_ = user_gesture;
window_features_ = std::move(window_features);
disposition_ = disposition;
std::move(test_callback_)
.Run(render_frame_host_->GetRenderWidgetHost()->GetRoutingID());
}
void ResumeShowCreatedWindow() {
GetForwardingInterface()->ShowCreatedWindow(
opener_frame_token_, disposition_, std::move(window_features_),
user_gesture_, std::move(show_callback_));
}
private:
raw_ptr<RenderFrameHostImpl> render_frame_host_;
base::OnceCallback<void(int32_t pending_widget_routing_id)> test_callback_;
ShowCreatedWindowCallback show_callback_;
blink::LocalFrameToken opener_frame_token_;
blink::mojom::WindowFeaturesPtr window_features_;
bool user_gesture_ = false;
WindowOpenDisposition disposition_;
mojo::test::ScopedSwapImplForTesting<
mojo::AssociatedReceiver<blink::mojom::LocalMainFrameHost>>
swapped_impl_;
};
class NewWindowCreatedObserver : public WebContentsObserver {
public:
NewWindowCreatedObserver(
WebContents* web_contents,
base::OnceCallback<void(int32_t pending_widget_routing_id)> test_callback)
: WebContentsObserver(web_contents),
test_callback_(std::move(test_callback)) {}
void DidOpenRequestedURL(WebContents* new_contents,
RenderFrameHost* source_render_frame_host,
const GURL& url,
const Referrer& referrer,
WindowOpenDisposition disposition,
ui::PageTransition transition,
bool started_from_context_menu,
bool renderer_initiated) override {
show_interceptor_ = std::make_unique<ShowCreatedWindowInterceptor>(
static_cast<RenderFrameHostImpl*>(new_contents->GetPrimaryMainFrame()),
std::move(test_callback_));
Observe(nullptr);
}
void ResumeShowCreatedWindow() {
show_interceptor_->ResumeShowCreatedWindow();
}
private:
std::unique_ptr<ShowCreatedWindowInterceptor> show_interceptor_;
base::OnceCallback<void(int32_t pending_widget_routing_id)> test_callback_;
};
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
TwoSubframesCreatePopupsSimultaneously) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b,c)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child1 = root->child_at(0);
FrameTreeNode* child2 = root->child_at(1);
RenderFrameHostImpl* frame1 = child1->current_frame_host();
RenderFrameHostImpl* frame2 = child2->current_frame_host();
RenderProcessHost* process1 = frame1->GetProcess();
RenderProcessHost* process2 = frame2->GetProcess();
base::RunLoop run_loop1;
int32_t routing_id1;
NewWindowCreatedObserver interceptor1(
web_contents(),
base::BindLambdaForTesting([&](int32_t pending_widget_routing_id) {
routing_id1 = pending_widget_routing_id;
run_loop1.Quit();
}));
EXPECT_TRUE(ExecJs(child1, "window.open();"));
run_loop1.Run();
base::RunLoop run_loop2;
int32_t routing_id2;
NewWindowCreatedObserver interceptor2(
web_contents(),
base::BindLambdaForTesting([&](int32_t pending_widget_routing_id) {
routing_id2 = pending_widget_routing_id;
run_loop2.Quit();
}));
EXPECT_TRUE(ExecJs(child2, "window.open();"));
run_loop2.Run();
EXPECT_TRUE(base::Contains(web_contents()->pending_contents_,
GlobalRoutingID(process1->GetID(), routing_id1)));
EXPECT_TRUE(base::Contains(web_contents()->pending_contents_,
GlobalRoutingID(process2->GetID(), routing_id2)));
EXPECT_EQ(routing_id1, routing_id2);
interceptor1.ResumeShowCreatedWindow();
interceptor2.ResumeShowCreatedWindow();
EXPECT_EQ(3u, Shell::windows().size());
}
class RequestCloseWidgetInterceptor
: public blink::mojom::PopupWidgetHostInterceptorForTesting {
public:
explicit RequestCloseWidgetInterceptor(
RenderWidgetHostImpl* render_widget_host)
: render_widget_host_(render_widget_host),
swapped_impl_(
render_widget_host_->popup_widget_host_receiver_for_testing(),
this) {}
~RequestCloseWidgetInterceptor() override = default;
blink::mojom::PopupWidgetHost* GetForwardingInterface() override {
return render_widget_host_;
}
void RequestClosePopup() override {}
private:
raw_ptr<RenderWidgetHostImpl> render_widget_host_;
mojo::test::ScopedSwapImplForTesting<
mojo::AssociatedReceiver<blink::mojom::PopupWidgetHost>>
swapped_impl_;
};
class ShowCreatedPopupWidgetInterceptor
: public blink::mojom::PopupWidgetHostInterceptorForTesting {
public:
ShowCreatedPopupWidgetInterceptor(
RenderWidgetHostImpl* render_widget_host,
base::OnceCallback<void(int32_t pending_widget_routing_id)> test_callback)
: render_widget_host_(render_widget_host),
test_callback_(std::move(test_callback)),
swapped_impl_(
render_widget_host_->popup_widget_host_receiver_for_testing(),
this) {}
~ShowCreatedPopupWidgetInterceptor() override = default;
blink::mojom::PopupWidgetHost* GetForwardingInterface() override {
return render_widget_host_;
}
void ShowPopup(const gfx::Rect& initial_rect,
const gfx::Rect& initial_anchor_rect,
ShowPopupCallback callback) override {
show_callback_ = std::move(callback);
initial_rect_ = initial_rect;
std::move(test_callback_).Run(render_widget_host_->GetRoutingID());
}
void ResumeShowPopupWidget() {
gfx::Rect anchor = initial_rect_;
anchor.set_size({1, 1});
GetForwardingInterface()->ShowPopup(initial_rect_, anchor,
std::move(show_callback_));
}
private:
raw_ptr<RenderWidgetHostImpl> render_widget_host_;
base::OnceCallback<void(int32_t pending_widget_routing_id)> test_callback_;
ShowPopupCallback show_callback_;
gfx::Rect initial_rect_;
mojo::test::ScopedSwapImplForTesting<
mojo::AssociatedReceiver<blink::mojom::PopupWidgetHost>>
swapped_impl_;
};
class NewPopupWidgetCreatedObserver {
public:
NewPopupWidgetCreatedObserver(
RenderFrameHostImpl* frame_host,
base::OnceCallback<void(int32_t pending_widget_routing_id)> test_callback)
: frame_host_(frame_host), test_callback_(std::move(test_callback)) {
frame_host_->SetCreateNewPopupCallbackForTesting(base::BindRepeating(
&NewPopupWidgetCreatedObserver::DidCreatePopupWidget,
base::Unretained(this)));
}
~NewPopupWidgetCreatedObserver() {
if (frame_host_)
frame_host_->SetCreateNewPopupCallbackForTesting(base::NullCallback());
}
void ResumeShowPopupWidget() { show_interceptor_->ResumeShowPopupWidget(); }
private:
void DidCreatePopupWidget(RenderWidgetHostImpl* widget) {
show_interceptor_ = std::make_unique<ShowCreatedPopupWidgetInterceptor>(
widget, std::move(test_callback_));
frame_host_->SetCreateNewPopupCallbackForTesting(base::NullCallback());
frame_host_ = nullptr;
}
raw_ptr<RenderFrameHostImpl> frame_host_;
std::unique_ptr<ShowCreatedPopupWidgetInterceptor> show_interceptor_;
base::OnceCallback<void(int32_t pending_widget_routing_id)> test_callback_;
};
#if !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_ANDROID)
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#define MAYBE_TwoSubframesCreatePopupMenuWidgetsSimultaneously \
DISABLED_TwoSubframesCreatePopupMenuWidgetsSimultaneously
#else
#define MAYBE_TwoSubframesCreatePopupMenuWidgetsSimultaneously \
TwoSubframesCreatePopupMenuWidgetsSimultaneously
#endif
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
MAYBE_TwoSubframesCreatePopupMenuWidgetsSimultaneously) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b,c)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child1 = root->child_at(0);
FrameTreeNode* child2 = root->child_at(1);
RenderProcessHost* process1 = child1->current_frame_host()->GetProcess();
RenderProcessHost* process2 = child2->current_frame_host()->GetProcess();
EXPECT_TRUE(NavigateToURLFromRenderer(
child1, embedded_test_server()->GetURL(
"b.com", "/site_isolation/page-with-select.html")));
EXPECT_TRUE(NavigateToURLFromRenderer(
child2, embedded_test_server()->GetURL(
"c.com", "/site_isolation/page-with-select.html")));
NativeWebKeyboardEvent event(
blink::WebKeyboardEvent::Type::kChar, blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests());
event.text[0] = ' ';
base::RunLoop run_loop1;
int32_t routing_id1;
NewPopupWidgetCreatedObserver interceptor1(
child1->current_frame_host(),
base::BindLambdaForTesting([&](int32_t pending_widget_routing_id) {
routing_id1 = pending_widget_routing_id;
run_loop1.Quit();
}));
EXPECT_TRUE(ExecJs(child1, "focusSelectMenu();"));
child1->current_frame_host()->GetRenderWidgetHost()->ForwardKeyboardEvent(
event);
run_loop1.Run();
auto first_popup_global_id = GlobalRoutingID(process1->GetID(), routing_id1);
EXPECT_TRUE(
base::Contains(web_contents()->pending_widgets_, first_popup_global_id));
RequestCloseWidgetInterceptor child1_popup_widget_interceptor(
static_cast<RenderWidgetHostImpl*>(
web_contents()->pending_widgets_[first_popup_global_id]));
base::RunLoop run_loop2;
int32_t routing_id2;
NewPopupWidgetCreatedObserver interceptor2(
child2->current_frame_host(),
base::BindLambdaForTesting([&](int32_t pending_widget_routing_id) {
routing_id2 = pending_widget_routing_id;
run_loop2.Quit();
}));
EXPECT_TRUE(ExecJs(child2, "focusSelectMenu();"));
child2->current_frame_host()->GetRenderWidgetHost()->ForwardKeyboardEvent(
event);
run_loop2.Run();
EXPECT_TRUE(
base::Contains(web_contents()->pending_widgets_, first_popup_global_id));
EXPECT_TRUE(base::Contains(web_contents()->pending_widgets_,
GlobalRoutingID(process2->GetID(), routing_id2)));
EXPECT_EQ(routing_id1, routing_id2);
interceptor1.ResumeShowPopupWidget();
interceptor2.ResumeShowPopupWidget();
EXPECT_FALSE(base::Contains(web_contents()->pending_widgets_,
GlobalRoutingID(process1->GetID(), routing_id1)));
EXPECT_FALSE(base::Contains(web_contents()->pending_widgets_,
GlobalRoutingID(process2->GetID(), routing_id2)));
RunPostedTasks();
}
#endif
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, FileChooserInSubframe) {
EXPECT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)")));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
GURL url(embedded_test_server()->GetURL("b.com", "/file_input.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), url));
base::RunLoop run_loop;
base::FilePath file;
EXPECT_TRUE(base::PathService::Get(base::DIR_TEMP, &file));
file = file.AppendASCII("bar");
std::unique_ptr<FileChooserDelegate> delegate(
new FileChooserDelegate(file, run_loop.QuitClosure()));
shell()->web_contents()->SetDelegate(delegate.get());
EXPECT_TRUE(ExecJs(root->child_at(0),
"document.getElementById('fileinput').click();"));
run_loop.Run();
EXPECT_EQ("bar",
EvalJs(root->child_at(0),
"document.getElementById('fileinput').files[0].name;"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
PendingRFHIsCanceledWhenItsProcessDies) {
GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
GURL popup_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
Shell* popup_shell = OpenPopup(root, popup_url, "foo");
EXPECT_TRUE(popup_shell);
SiteInstanceGroup* b_group =
static_cast<SiteInstanceImpl*>(
popup_shell->web_contents()->GetSiteInstance())
->group();
RenderViewHostImpl* rvh =
web_contents()->GetPrimaryFrameTree().GetRenderViewHost(b_group).get();
EXPECT_FALSE(rvh->is_active());
GURL stall_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
TestNavigationManager delayer(shell()->web_contents(), stall_url);
EXPECT_TRUE(ExecJs(shell(), JsReplace("location = $1", stall_url)));
EXPECT_TRUE(delayer.WaitForRequestStart());
RenderFrameHostImpl* pending_rfh =
root->render_manager()->speculative_frame_host();
RenderProcessHost* pending_process = pending_rfh->GetProcess();
EXPECT_EQ(pending_process,
popup_shell->web_contents()->GetPrimaryMainFrame()->GetProcess());
RenderProcessHostWatcher crash_observer(
pending_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
EXPECT_TRUE(pending_process->Shutdown(0));
crash_observer.Wait();
EXPECT_FALSE(root->render_manager()->speculative_frame_host());
GURL b_url(embedded_test_server()->GetURL("b.com", "/title3.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(shell(), b_url));
EXPECT_TRUE(rvh->is_active());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
RenderViewHostKeepsSwappedOutStateIfPendingRFHDies) {
GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
GURL popup_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
Shell* popup_shell = OpenPopup(root, popup_url, "foo");
EXPECT_TRUE(popup_shell);
SiteInstanceGroup* b_group =
static_cast<SiteInstanceImpl*>(
popup_shell->web_contents()->GetSiteInstance())
->group();
RenderViewHostImpl* rvh =
web_contents()->GetPrimaryFrameTree().GetRenderViewHost(b_group).get();
EXPECT_FALSE(rvh->is_active());
GURL stall_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
NavigationHandleObserver handle_observer(shell()->web_contents(), stall_url);
TestNavigationManager delayer(shell()->web_contents(), stall_url);
EXPECT_TRUE(ExecJs(shell(), JsReplace("location = $1", stall_url)));
EXPECT_TRUE(delayer.WaitForRequestStart());
RenderProcessHost* pending_process =
popup_shell->web_contents()->GetPrimaryMainFrame()->GetProcess();
RenderProcessHostWatcher crash_observer(
pending_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
EXPECT_TRUE(pending_process->Shutdown(0));
crash_observer.Wait();
EXPECT_FALSE(rvh->is_active());
EXPECT_EQ(net::ERR_ABORTED, handle_observer.net_error_code());
GURL b_url(embedded_test_server()->GetURL("b.com", "/title3.html"));
EXPECT_TRUE(NavigateToURLInSameBrowsingInstance(popup_shell, b_url));
EXPECT_FALSE(rvh->is_active());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
NavigateCrashedSubframeToSameSite) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child = root->child_at(0);
EXPECT_TRUE(ExecJs(
root->current_frame_host(),
"window.addEventListener('message',"
" function(e) { document.title = e.data; });"));
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();
EXPECT_FALSE(child->current_frame_host()->IsRenderFrameLive());
EXPECT_FALSE(child->current_frame_host()->GetView());
RenderFrameProxyHost* proxy_to_parent =
child->render_manager()->GetProxyToParent();
EXPECT_FALSE(
proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
NavigateFrameToURL(child,
embedded_test_server()->GetURL("b.com", "/title1.html"));
EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive());
EXPECT_TRUE(child->current_frame_host()->GetView());
EXPECT_EQ(
child->current_frame_host()->GetView(),
proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
RenderFrameSubmissionObserver frame_observer(child);
frame_observer.WaitForMetadataChange();
std::u16string expected_title(u"I am alive!");
TitleWatcher title_watcher(shell()->web_contents(), expected_title);
EXPECT_TRUE(ExecJs(child->current_frame_host(),
"parent.postMessage('I am alive!', '*');"));
EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, SessionHistoryReplication) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a,a)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child1 = root->child_at(0);
FrameTreeNode* child2 = root->child_at(1);
GURL child_first_url(child1->current_url());
EXPECT_EQ(child1->current_url(), child2->current_url());
auto history_length = [](FrameTreeNode* ftn) {
return EvalJs(ftn->current_frame_host(), "history.length;");
};
EXPECT_EQ(1, history_length(root));
EXPECT_EQ(1, history_length(child1));
EXPECT_EQ(1, history_length(child2));
EXPECT_TRUE(NavigateToURLFromRenderer(
child1, embedded_test_server()->GetURL("b.com", "/title1.html")));
EXPECT_EQ(2, history_length(root));
EXPECT_EQ(2, history_length(child1));
EXPECT_EQ(2, history_length(child2));
GURL child2_last_url(embedded_test_server()->GetURL("a.com", "/title2.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(child2, child2_last_url));
EXPECT_EQ(3, history_length(root));
EXPECT_EQ(3, history_length(child1));
EXPECT_EQ(3, history_length(child2));
GURL child1_last_url(embedded_test_server()->GetURL("b.com", "/title3.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(child1, child1_last_url));
EXPECT_EQ(4, history_length(root));
EXPECT_EQ(4, history_length(child1));
EXPECT_EQ(4, history_length(child2));
EXPECT_TRUE(ExecJs(root, "history.go(-3);"));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(main_url, root->current_url());
EXPECT_EQ(child_first_url, child1->current_url());
EXPECT_EQ(child_first_url, child2->current_url());
EXPECT_TRUE(ExecJs(child1, "history.go(3);"));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(main_url, root->current_url());
EXPECT_EQ(child1_last_url, child1->current_url());
EXPECT_EQ(child2_last_url, child2->current_url());
}
class DispatchLoadInterceptor
: public blink::mojom::LocalFrameHostInterceptorForTesting {
public:
explicit DispatchLoadInterceptor(RenderFrameHostImpl* render_frame_host)
: render_frame_host_(render_frame_host),
swapped_impl_(
render_frame_host_->local_frame_host_receiver_for_testing(),
this) {}
~DispatchLoadInterceptor() override = default;
LocalFrameHost* GetForwardingInterface() override {
return render_frame_host_;
}
void DispatchLoad() override {}
private:
raw_ptr<RenderFrameHostImpl> render_frame_host_;
mojo::test::ScopedSwapImplForTesting<
mojo::AssociatedReceiver<blink::mojom::LocalFrameHost>>
swapped_impl_;
};
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
LoadEventForwardingWhilePendingDeletion) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child = root->child_at(0);
GURL popup_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
Shell* popup_shell = OpenPopup(root, popup_url, "foo");
EXPECT_TRUE(popup_shell);
GURL b_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
{
TestFrameNavigationObserver commit_observer(child);
EXPECT_TRUE(ExecJs(child, JsReplace("location.href = $1", b_url)));
commit_observer.WaitForCommit();
}
RenderFrameHostImpl* child_rfh = child->current_frame_host();
child_rfh->DisableUnloadTimerForTesting();
EXPECT_TRUE(child->render_manager()->GetProxyToParent());
{
DispatchLoadInterceptor interceptor(child_rfh);
{
TestFrameNavigationObserver commit_observer(child);
web_contents()->GetController().GoBack();
commit_observer.WaitForCommit();
}
EXPECT_TRUE(child_rfh->IsPendingDeletion());
EXPECT_FALSE(child->render_manager()->GetProxyToParent());
child_rfh->DispatchLoad();
}
EXPECT_TRUE(ExecJs(popup_shell->web_contents(), "true"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
RFHTransfersWhilePendingDeletion) {
GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL cross_site_url_1 =
embedded_test_server()->GetURL("b.com", "/title1.html");
TestNavigationManager cross_site_manager(shell()->web_contents(),
cross_site_url_1);
shell()->web_contents()->GetController().LoadURL(
cross_site_url_1, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
EXPECT_TRUE(cross_site_manager.WaitForResponse());
GURL cross_site_url_2 =
embedded_test_server()->GetURL("c.com", "/title1.html");
TestNavigationManager transfer_manager(shell()->web_contents(),
cross_site_url_2);
EXPECT_TRUE(ExecJs(root, JsReplace("location.href = $1", cross_site_url_2)));
EXPECT_TRUE(transfer_manager.WaitForResponse());
ASSERT_TRUE(cross_site_manager.WaitForNavigationFinished());
ASSERT_TRUE(transfer_manager.WaitForNavigationFinished());
}
class NavigationHandleWatcher : public WebContentsObserver {
public:
explicit NavigationHandleWatcher(WebContents* web_contents)
: WebContentsObserver(web_contents) {}
void DidStartNavigation(NavigationHandle* navigation_handle) override {
DCHECK_EQ(GURL("http://b.com/"),
navigation_handle->GetStartingSiteInstance()->GetSiteURL());
}
};
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
NavigationHandleSiteInstance) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
NavigationHandleWatcher watcher(shell()->web_contents());
TestNavigationObserver load_observer(shell()->web_contents());
GURL frame_url = embedded_test_server()->GetURL("c.com", "/title1.html");
EXPECT_TRUE(ExecJs(shell()->web_contents(),
JsReplace("window.frames[0].location = $1", frame_url)));
load_observer.Wait();
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
ReuseNonLiveRenderViewHostAfterCancelPending) {
GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL b_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
GURL c_url(embedded_test_server()->GetURL("c.com", "/title3.html"));
EXPECT_TRUE(NavigateToURL(shell(), a_url));
Shell* popup = OpenPopup(shell(), a_url, "popup");
EXPECT_TRUE(NavigateToURLFromRenderer(popup, b_url));
Shell* popup2 = OpenPopup(shell(), a_url, "popup2");
TestNavigationObserver observer(popup2->web_contents());
GURL redirect_url(embedded_test_server()->GetURL(
"b.com", "/server-redirect?" + c_url.spec()));
EXPECT_FALSE(NavigateToURLFromRenderer(popup2, redirect_url));
EXPECT_EQ(c_url, observer.last_navigation_url());
EXPECT_TRUE(observer.last_navigation_succeeded());
RenderProcessHost* b_process =
popup->web_contents()->GetPrimaryMainFrame()->GetProcess();
RenderProcessHostWatcher crash_observer(
b_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
b_process->Shutdown(0);
crash_observer.Wait();
EXPECT_TRUE(NavigateToURLInSameBrowsingInstance(popup2, b_url));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
RecreateMainFrameAfterCancelPending) {
GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL b_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
GURL c_url(embedded_test_server()->GetURL("c.com", "/title3.html"));
EXPECT_TRUE(NavigateToURL(shell(), a_url));
Shell* popup = OpenPopup(shell(), a_url, "popup");
EXPECT_TRUE(NavigateToURLFromRenderer(popup, b_url));
Shell* popup2 = OpenPopup(shell(), a_url, "popup2");
TestNavigationObserver observer(popup2->web_contents());
GURL redirect_url(embedded_test_server()->GetURL(
"b.com", "/server-redirect?" + c_url.spec()));
EXPECT_FALSE(NavigateToURLFromRenderer(popup2, redirect_url));
EXPECT_EQ(c_url, observer.last_navigation_url());
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_TRUE(NavigateToURLFromRenderer(popup2, b_url));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
CommunicateWithProxyAfterCancelPending) {
GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
GURL b_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
GURL c_url(embedded_test_server()->GetURL("c.com", "/title3.html"));
EXPECT_TRUE(NavigateToURL(shell(), a_url));
Shell* popup = OpenPopup(shell(), a_url, "popup");
EXPECT_TRUE(NavigateToURLFromRenderer(popup, b_url));
Shell* popup2 = OpenPopup(shell(), a_url, "popup2");
TestNavigationObserver observer(popup2->web_contents());
GURL redirect_url(embedded_test_server()->GetURL(
"b.com", "/server-redirect?" + c_url.spec()));
EXPECT_FALSE(NavigateToURLFromRenderer(popup2, redirect_url));
EXPECT_EQ(c_url, observer.last_navigation_url());
EXPECT_TRUE(observer.last_navigation_succeeded());
SiteInstance* b_instance = popup->web_contents()->GetSiteInstance();
FrameTreeNode* popup2_root =
static_cast<WebContentsImpl*>(popup2->web_contents())
->GetPrimaryFrameTree()
.root();
RenderFrameProxyHost* proxy =
popup2_root->current_frame_host()
->browsing_context_state()
->GetRenderFrameProxyHost(
static_cast<SiteInstanceImpl*>(b_instance)->group());
EXPECT_TRUE(proxy);
EXPECT_TRUE(proxy->is_render_frame_proxy_live());
EXPECT_TRUE(ExecJs(popup2,
"window.addEventListener('message', function(event) {\n"
" document.title=event.data;\n"
"});"));
EXPECT_TRUE(NavigateToURLFromRenderer(shell(), b_url));
std::u16string expected_title(u"foo");
TitleWatcher title_watcher(popup2->web_contents(), expected_title);
EXPECT_TRUE(
ExecJs(shell(), "window.open('','popup2').postMessage('foo', '*');"));
EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
HeaderPolicyOnXSLTNavigation) {
GURL url(embedded_test_server()->GetURL("a.com", "/permissions-policy.xml"));
EXPECT_TRUE(NavigateToURL(shell(), url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(CreateParsedPermissionsPolicyMatchesSelf(
{blink::mojom::PermissionsPolicyFeature::kGeolocation},
url.DeprecatedGetOriginAsURL()),
root->current_replication_state().permissions_policy_header);
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
TestPolicyReplicationOnSameOriginNavigation) {
GURL start_url(
embedded_test_server()->GetURL("a.com", "/permissions-policy1.html"));
GURL first_nav_url(
embedded_test_server()->GetURL("a.com", "/permissions-policy2.html"));
GURL second_nav_url(embedded_test_server()->GetURL("a.com", "/title2.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(CreateParsedPermissionsPolicyMatchesSelf(
{blink::mojom::PermissionsPolicyFeature::kGeolocation,
blink::mojom::PermissionsPolicyFeature::kPayment},
start_url.DeprecatedGetOriginAsURL()),
root->current_replication_state().permissions_policy_header);
EXPECT_TRUE(NavigateToURL(shell(), first_nav_url));
EXPECT_EQ(CreateParsedPermissionsPolicyMatchesAll(
{blink::mojom::PermissionsPolicyFeature::kGeolocation,
blink::mojom::PermissionsPolicyFeature::kPayment}),
root->current_replication_state().permissions_policy_header);
EXPECT_TRUE(NavigateToURL(shell(), second_nav_url));
EXPECT_TRUE(
root->current_replication_state().permissions_policy_header.empty());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
TestPolicyReplicationOnCrossOriginNavigation) {
GURL start_url(
embedded_test_server()->GetURL("a.com", "/permissions-policy1.html"));
GURL first_nav_url(
embedded_test_server()->GetURL("b.com", "/permissions-policy2.html"));
GURL second_nav_url(embedded_test_server()->GetURL("c.com", "/title2.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(CreateParsedPermissionsPolicyMatchesSelf(
{blink::mojom::PermissionsPolicyFeature::kGeolocation,
blink::mojom::PermissionsPolicyFeature::kPayment},
start_url.DeprecatedGetOriginAsURL()),
root->current_replication_state().permissions_policy_header);
EXPECT_TRUE(NavigateToURL(shell(), first_nav_url));
EXPECT_EQ(CreateParsedPermissionsPolicyMatchesAll(
{blink::mojom::PermissionsPolicyFeature::kGeolocation,
blink::mojom::PermissionsPolicyFeature::kPayment}),
root->current_replication_state().permissions_policy_header);
EXPECT_TRUE(NavigateToURL(shell(), second_nav_url));
EXPECT_TRUE(
root->current_replication_state().permissions_policy_header.empty());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
TestPolicyReplicationFromRemoteFrames) {
GURL main_url(
embedded_test_server()->GetURL("a.com", "/permissions-policy-main.html"));
GURL first_nav_url(
embedded_test_server()->GetURL("b.com", "/permissions-policy2.html"));
GURL second_nav_url(embedded_test_server()->GetURL("c.com", "/title2.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(CreateParsedPermissionsPolicy(
{blink::mojom::PermissionsPolicyFeature::kGeolocation,
blink::mojom::PermissionsPolicyFeature::kPayment},
{GURL("http://example.com/")}, false,
main_url.DeprecatedGetOriginAsURL()),
root->current_replication_state().permissions_policy_header);
EXPECT_EQ(1UL, root->child_count());
EXPECT_EQ(
CreateParsedPermissionsPolicyMatchesSelf(
{blink::mojom::PermissionsPolicyFeature::kGeolocation,
blink::mojom::PermissionsPolicyFeature::kPayment},
main_url.DeprecatedGetOriginAsURL()),
root->child_at(0)->current_replication_state().permissions_policy_header);
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), first_nav_url));
EXPECT_EQ(
CreateParsedPermissionsPolicyMatchesAll(
{blink::mojom::PermissionsPolicyFeature::kGeolocation,
blink::mojom::PermissionsPolicyFeature::kPayment}),
root->child_at(0)->current_replication_state().permissions_policy_header);
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), second_nav_url));
EXPECT_TRUE(root->child_at(0)
->current_replication_state()
.permissions_policy_header.empty());
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), first_nav_url));
EXPECT_EQ(
CreateParsedPermissionsPolicyMatchesAll(
{blink::mojom::PermissionsPolicyFeature::kGeolocation,
blink::mojom::PermissionsPolicyFeature::kPayment}),
root->child_at(0)->current_replication_state().permissions_policy_header);
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
TestPermissionsPolicyReplicationToProxyOnNavigation) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/frame_tree/page_with_two_frames.html"));
GURL first_nav_url(
embedded_test_server()->GetURL("a.com", "/permissions-policy3.html"));
GURL second_nav_url(
embedded_test_server()->GetURL("a.com", "/permissions-policy4.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_TRUE(
root->current_replication_state().permissions_policy_header.empty());
EXPECT_EQ(2UL, root->child_count());
EXPECT_TRUE(root->child_at(1)
->current_replication_state()
.permissions_policy_header.empty());
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(1), first_nav_url));
EXPECT_EQ(
CreateParsedPermissionsPolicyMatchesNone(
{blink::mojom::PermissionsPolicyFeature::kGeolocation,
blink::mojom::PermissionsPolicyFeature::kPayment}),
root->child_at(1)->current_replication_state().permissions_policy_header);
EXPECT_EQ(1UL, root->child_at(1)->child_count());
EXPECT_EQ(false,
EvalJs(root->child_at(1)->child_at(0),
"document.featurePolicy.allowsFeature('geolocation')"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(1), second_nav_url));
EXPECT_TRUE(root->child_at(1)
->current_replication_state()
.permissions_policy_header.empty());
EXPECT_EQ(1UL, root->child_at(1)->child_count());
EXPECT_EQ(true,
EvalJs(root->child_at(1)->child_at(0),
"document.featurePolicy.allowsFeature('geolocation')"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
TestAllowAttributeInSandboxedFrame) {
GURL main_url(embedded_test_server()->GetURL(
"a.com",
"/cross_site_iframe_factory.html?"
"a(b{allow-geolocation,sandbox-allow-scripts})"));
GURL nav_url(embedded_test_server()->GetURL("c.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_TRUE(
root->current_replication_state().permissions_policy_header.empty());
EXPECT_EQ(1UL, root->child_count());
EXPECT_TRUE(root->child_at(0)
->current_frame_host()
->GetLastCommittedOrigin()
.opaque());
EXPECT_TRUE(root->child_at(0)->current_origin().opaque());
EXPECT_EQ(true,
EvalJs(root->child_at(0),
"document.featurePolicy.allowsFeature('geolocation');"));
TestNavigationObserver load_observer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root->child_at(0),
JsReplace("document.location.href=$1", nav_url)));
load_observer.Wait();
EXPECT_TRUE(root->child_at(0)
->current_frame_host()
->GetLastCommittedOrigin()
.opaque());
EXPECT_TRUE(root->child_at(0)->current_origin().opaque());
EXPECT_EQ(true,
EvalJs(root->child_at(0),
"document.featurePolicy.allowsFeature('geolocation');"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
TestAllowAttributeInOpaqueOriginAfterNavigation) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/page_with_data_iframe_and_allow.html"));
GURL nav_url(embedded_test_server()->GetURL("c.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_TRUE(
root->current_replication_state().permissions_policy_header.empty());
EXPECT_EQ(1UL, root->child_count());
EXPECT_TRUE(root->child_at(0)
->current_frame_host()
->GetLastCommittedOrigin()
.opaque());
EXPECT_TRUE(root->child_at(0)->current_origin().opaque());
EXPECT_EQ(true,
EvalJs(root->child_at(0),
"document.featurePolicy.allowsFeature('geolocation');"));
TestNavigationObserver load_observer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root->child_at(0),
JsReplace("document.location.href=$1", nav_url)));
load_observer.Wait();
EXPECT_FALSE(root->child_at(0)
->current_frame_host()
->GetLastCommittedOrigin()
.opaque());
EXPECT_FALSE(root->child_at(0)->current_origin().opaque());
EXPECT_EQ(false,
EvalJs(root->child_at(0),
"document.featurePolicy.allowsFeature('geolocation');"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
IframeSrcdocAfterCrossSiteNavigation) {
GURL parent_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
GURL child_url(embedded_test_server()->GetURL(
"b.com", "/cross_site_iframe_factory.html?b()"));
EXPECT_TRUE(NavigateToURL(shell(), parent_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
ASSERT_EQ(1u, root->child_count());
FrameTreeNode* child = root->child_at(0);
EXPECT_EQ(parent_url, root->current_url());
EXPECT_EQ(child_url, child->current_url());
EXPECT_NE(root->current_frame_host()->GetSiteInstance(),
child->current_frame_host()->GetSiteInstance());
EXPECT_NE(root->current_frame_host()->GetProcess(),
child->current_frame_host()->GetProcess());
TestNavigationObserver load_observer(shell()->web_contents());
EXPECT_TRUE(ExecJs(
root, "document.getElementById('child-0').srcdoc = 'srcdoc content';"));
load_observer.Wait();
EXPECT_TRUE(child->current_url().IsAboutSrcdoc());
EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
child->current_frame_host()->GetSiteInstance());
EXPECT_EQ(root->current_frame_host()->GetProcess(),
child->current_frame_host()->GetProcess());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
RemoteToLocalNavigationInCrashedSubframe) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child = root->child_at(0);
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();
}
EXPECT_FALSE(child->current_frame_host()->IsRenderFrameLive());
TestFrameNavigationObserver frame_observer(child);
GURL frame_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(ExecJs(
root, JsReplace("document.querySelector('iframe').src = $1", frame_url)));
frame_observer.Wait();
EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive());
EXPECT_FALSE(child->IsLoading());
EXPECT_EQ(child->current_frame_host()->GetSiteInstance(),
root->current_frame_host()->GetSiteInstance());
EXPECT_EQ(1, EvalJs(root, "frames.length;"));
EXPECT_EQ("This page has no title.",
EvalJs(root, "frames[0].document.body.innerText;"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
ContextMenuAfterCrossProcessNavigation) {
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(
shell()->web_contents()->GetPrimaryMainFrame());
auto unload_ack_filter = base::BindRepeating([] { return true; });
rfh->SetUnloadACKCallbackForTesting(unload_ack_filter);
rfh->DisableUnloadTimerForTesting();
OpenPopup(shell(), embedded_test_server()->GetURL("a.com", "/title2.html"),
"foo");
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL("b.com", "/title3.html")));
rfh->ShowContextMenu(mojo::NullAssociatedRemote(), ContextMenuParams());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, ContainerPolicy) {
GURL url(embedded_test_server()->GetURL("/allowed_frames.html"));
EXPECT_TRUE(NavigateToURL(shell(), url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(0UL, root->effective_frame_policy().container_policy.size());
EXPECT_EQ(
0UL, root->child_at(0)->effective_frame_policy().container_policy.size());
EXPECT_EQ(
0UL, root->child_at(1)->effective_frame_policy().container_policy.size());
EXPECT_EQ(
2UL, root->child_at(2)->effective_frame_policy().container_policy.size());
EXPECT_EQ(
2UL, root->child_at(3)->effective_frame_policy().container_policy.size());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, ContainerPolicyDynamic) {
GURL main_url(embedded_test_server()->GetURL("/allowed_frames.html"));
GURL nav_url(
embedded_test_server()->GetURL("b.com", "/permissions-policy2.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(
2UL, root->child_at(2)->effective_frame_policy().container_policy.size());
EXPECT_TRUE(ExecJs(
root, "document.getElementById('child-2').setAttribute('allow','')"));
EXPECT_EQ(
2UL, root->child_at(2)->effective_frame_policy().container_policy.size());
EXPECT_EQ(0UL,
root->child_at(2)->pending_frame_policy().container_policy.size());
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(2), nav_url));
EXPECT_EQ(
0UL, root->child_at(2)->effective_frame_policy().container_policy.size());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
ContainerPolicyCrossOriginNavigation) {
WebContentsImpl* contents = web_contents();
FrameTreeNode* root = contents->GetPrimaryFrameTree().root();
auto is_fullscreen_allowed = [](FrameTreeNode* ftn) {
return EvalJs(ftn, "document.webkitFullscreenEnabled;");
};
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)")));
EXPECT_TRUE(ExecJs(
root, "document.getElementById('child-0').allowFullscreen='true'"));
EXPECT_EQ(false, is_fullscreen_allowed(root->child_at(0)));
EXPECT_TRUE(NavigateToURLFromRenderer(
root->child_at(0),
embedded_test_server()->GetURL("c.com", "/title1.html")));
EXPECT_EQ(true, is_fullscreen_allowed(root->child_at(0)));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
ContainerPolicySandboxDynamic) {
GURL main_url(embedded_test_server()->GetURL("/allowed_frames.html"));
GURL nav_url(
embedded_test_server()->GetURL("b.com", "/permissions-policy2.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
const blink::ParsedPermissionsPolicy initial_effective_policy =
root->child_at(2)->effective_frame_policy().container_policy;
EXPECT_EQ(1UL, initial_effective_policy[0].allowed_origins.size());
EXPECT_TRUE(ExecJs(
root, "document.getElementById('child-2').setAttribute('sandbox','')"));
const blink::ParsedPermissionsPolicy updated_effective_policy =
root->child_at(2)->effective_frame_policy().container_policy;
const blink::ParsedPermissionsPolicy updated_pending_policy =
root->child_at(2)->pending_frame_policy().container_policy;
EXPECT_EQ(1UL, updated_effective_policy[0].allowed_origins.size());
EXPECT_TRUE(updated_pending_policy[0].matches_opaque_src);
EXPECT_EQ(0UL, updated_pending_policy[0].allowed_origins.size());
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(2), nav_url));
const blink::ParsedPermissionsPolicy final_effective_policy =
root->child_at(2)->effective_frame_policy().container_policy;
EXPECT_TRUE(final_effective_policy[0].matches_opaque_src);
EXPECT_EQ(0UL, final_effective_policy[0].allowed_origins.size());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
PermissionsPolicyConstructionInExistingProxy) {
WebContentsImpl* contents = web_contents();
FrameTreeNode* root = contents->GetPrimaryFrameTree().root();
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)")));
// b.com(2) a.com(3)
// b.com(4)
auto create_subframe_script = JsReplace(
"var f = document.createElement('iframe'); f.src=$1; "
"document.body.appendChild(f);",
embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b{allow-autoplay})"));
EXPECT_TRUE(ExecJs(root, create_subframe_script));
EXPECT_TRUE(WaitForLoadStop(contents));
EXPECT_EQ(2UL, root->child_count());
EXPECT_EQ(1UL, root->child_at(1)->child_count());
EXPECT_EQ(true, EvalJs(root->child_at(1)->child_at(0),
"document.featurePolicy.allowsFeature('autoplay');"));
}
class RequestDelayingSitePerProcessBrowserTest
: public SitePerProcessBrowserTest {
public:
RequestDelayingSitePerProcessBrowserTest()
: test_server_(std::make_unique<net::EmbeddedTestServer>()) {}
void SetUpEmbeddedTestServer() {
SetupCrossSiteRedirector(test_server_.get());
test_server_->RegisterRequestHandler(base::BindRepeating(
&RequestDelayingSitePerProcessBrowserTest::HandleMockResource,
base::Unretained(this)));
ASSERT_TRUE(test_server_->Start());
}
void SetDelayedRequestsForPath(const std::string& path, int num_delayed) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!test_server_->Started());
num_remaining_requests_to_delay_for_path_[path] = num_delayed;
}
private:
void AddDelayedResponse(
base::WeakPtr<net::test_server::HttpResponseDelegate> delegate) {
response_closures_.push_back(base::BindOnce(
&net::test_server::HttpResponseDelegate::SendHeadersContentAndFinish,
delegate, net::HTTP_OK, "OK", base::StringPairs(), ""));
}
std::unique_ptr<net::test_server::HttpResponse> HandleMockResource(
const net::test_server::HttpRequest& request) {
auto it =
num_remaining_requests_to_delay_for_path_.find(request.GetURL().path());
if (it == num_remaining_requests_to_delay_for_path_.end())
return nullptr;
if (it->second > 0) {
--it->second;
return std::make_unique<DelayedResponse>(this);
}
MaybeStartRequests();
return nullptr;
}
void MaybeStartRequests() {
for (auto it : num_remaining_requests_to_delay_for_path_) {
if (it.second > 0)
return;
}
for (auto& it : response_closures_)
std::move(it).Run();
}
class DelayedResponse : public net::test_server::BasicHttpResponse {
public:
explicit DelayedResponse(
RequestDelayingSitePerProcessBrowserTest* test_harness)
: test_harness_(test_harness) {}
DelayedResponse(const DelayedResponse&) = delete;
DelayedResponse& operator=(const DelayedResponse&) = delete;
void SendResponse(base::WeakPtr<net::test_server::HttpResponseDelegate>
delegate) override {
test_harness_->AddDelayedResponse(delegate);
}
private:
raw_ptr<RequestDelayingSitePerProcessBrowserTest> test_harness_;
};
std::vector<base::OnceClosure> response_closures_;
std::map<std::string, int> num_remaining_requests_to_delay_for_path_;
std::unique_ptr<net::EmbeddedTestServer> test_server_;
};
IN_PROC_BROWSER_TEST_P(RequestDelayingSitePerProcessBrowserTest,
DelayableSubframeRequestsOneFrame) {
std::string path = "/mock-video.mp4";
SetDelayedRequestsForPath(path, 2);
SetUpEmbeddedTestServer();
GURL url(embedded_test_server()->GetURL(
"a.com", base::StringPrintf("/site_isolation/"
"subframes_with_resources.html?urls=%s&"
"numSubresources=3",
path.c_str())));
EXPECT_TRUE(NavigateToURL(shell(), url));
EXPECT_EQ(true, EvalJs(shell(), "createFrames()"));
}
IN_PROC_BROWSER_TEST_P(RequestDelayingSitePerProcessBrowserTest,
DelayableSubframeRequestsTwoFrames) {
std::string path0 = "/mock-video0.mp4";
std::string path1 = "/mock-video1.mp4";
SetDelayedRequestsForPath(path0, 2);
SetDelayedRequestsForPath(path1, 2);
SetUpEmbeddedTestServer();
GURL url(embedded_test_server()->GetURL(
"a.com", base::StringPrintf("/site_isolation/"
"subframes_with_resources.html?urls=%s,%s&"
"numSubresources=3",
path0.c_str(), path1.c_str())));
EXPECT_TRUE(NavigateToURL(shell(), url));
EXPECT_EQ(true, EvalJs(shell(), "createFrames()"));
}
#if BUILDFLAG(IS_ANDROID)
class TextSelectionObserver : public TextInputManager::Observer {
public:
explicit TextSelectionObserver(TextInputManager* text_input_manager)
: text_input_manager_(text_input_manager) {
text_input_manager->AddObserver(this);
}
TextSelectionObserver(const TextSelectionObserver&) = delete;
TextSelectionObserver& operator=(const TextSelectionObserver&) = delete;
~TextSelectionObserver() { text_input_manager_->RemoveObserver(this); }
void WaitForSelectedText(const std::string& expected_text) {
if (last_selected_text_ == expected_text)
return;
expected_text_ = expected_text;
loop_runner_ = new MessageLoopRunner();
loop_runner_->Run();
}
private:
void OnTextSelectionChanged(TextInputManager* text_input_manager,
RenderWidgetHostViewBase* updated_view) override {
last_selected_text_ = base::UTF16ToUTF8(
text_input_manager->GetTextSelection(updated_view)->selected_text());
if (last_selected_text_ == expected_text_ && loop_runner_)
loop_runner_->Quit();
}
const raw_ptr<TextInputManager> text_input_manager_;
std::string last_selected_text_;
std::string expected_text_;
scoped_refptr<MessageLoopRunner> loop_runner_;
};
class SitePerProcessAndroidImeTest : public SitePerProcessBrowserTest {
public:
SitePerProcessAndroidImeTest() : SitePerProcessBrowserTest() {}
SitePerProcessAndroidImeTest(const SitePerProcessAndroidImeTest&) = delete;
SitePerProcessAndroidImeTest& operator=(const SitePerProcessAndroidImeTest&) =
delete;
~SitePerProcessAndroidImeTest() override {}
protected:
ImeAdapterAndroid* ime_adapter() {
return static_cast<RenderWidgetHostViewAndroid*>(
web_contents()->GetRenderWidgetHostView())
->ime_adapter_for_testing();
}
void FocusInputInFrame(RenderFrameHostImpl* frame) {
ASSERT_TRUE(ExecJs(frame, "window.focus(); input.focus();"));
}
void LoadPage() {
ASSERT_TRUE(NavigateToURL(
shell(),
GURL(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b,c(a(b)))"))));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
frames_.push_back(root->current_frame_host());
frames_.push_back(root->child_at(0)->current_frame_host());
frames_.push_back(root->child_at(1)->current_frame_host());
frames_.push_back(root->child_at(1)->child_at(0)->current_frame_host());
frames_.push_back(
root->child_at(1)->child_at(0)->child_at(0)->current_frame_host());
std::string add_input_script =
"var input = document.createElement('input');"
"document.body.appendChild(input);"
"window.oninput = function() {"
" input.select();"
"};";
for (auto* frame : frames_)
ASSERT_TRUE(ExecJs(frame, add_input_script));
}
void CommitText(const char* text) {
JNIEnv* env = base::android::AttachCurrentThread();
base::android::ScopedJavaLocalRef<jobject> caller =
ime_adapter()->java_ime_adapter_for_testing(env);
base::android::ScopedJavaLocalRef<jstring> jtext =
base::android::ConvertUTF8ToJavaString(env, text);
ime_adapter()->CommitText(
env, base::android::JavaParamRef<jobject>(env, caller.obj()),
base::android::JavaParamRef<jobject>(env, jtext.obj()),
base::android::JavaParamRef<jstring>(env, jtext.obj()), 0);
}
std::vector<RenderFrameHostImpl*> frames_;
};
IN_PROC_BROWSER_TEST_P(SitePerProcessAndroidImeTest,
CommitTextForFocusedWidget) {
LoadPage();
TextSelectionObserver selection_observer(
web_contents()->GetTextInputManager());
for (size_t index = 0; index < frames_.size(); ++index) {
std::string text = base::StringPrintf("text%zu", index);
FocusInputInFrame(frames_[index]);
CommitText(text.c_str());
selection_observer.WaitForSelectedText(text);
}
}
#endif
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
SubframeTransfersToCurrentRFH) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
ASSERT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
scoped_refptr<SiteInstanceImpl> b_site_instance =
root->child_at(0)->current_frame_host()->GetSiteInstance();
GURL frame_url(
embedded_test_server()->GetURL("a.com", "/cross-site/b.com/title2.html"));
NavigateIframeToURL(shell()->web_contents(), "child-0", frame_url);
EXPECT_FALSE(root->child_at(0)->render_manager()->speculative_frame_host());
GURL redirected_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
EXPECT_EQ(root->child_at(0)->current_url(), redirected_url);
EXPECT_EQ(b_site_instance,
root->child_at(0)->current_frame_host()->GetSiteInstance());
NavigateFrameToURL(root->child_at(0), frame_url);
EXPECT_FALSE(root->child_at(0)->render_manager()->speculative_frame_host());
EXPECT_EQ(root->child_at(0)->current_url(), redirected_url);
EXPECT_EQ(b_site_instance,
root->child_at(0)->current_frame_host()->GetSiteInstance());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
FrameSwapPreservesUniqueName) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
ASSERT_TRUE(NavigateToURL(shell(), main_url));
{
GURL url(embedded_test_server()->GetURL("b.com", "/title1.html"));
EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "child-0", url));
}
{
GURL url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "child-0", url));
}
{
GURL url(embedded_test_server()->GetURL("b.com", "/title1.html"));
EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "child-0", url));
}
auto& controller = static_cast<NavigationControllerImpl&>(
shell()->web_contents()->GetController());
EXPECT_EQ(4, controller.GetEntryCount());
std::set<std::string> names;
for (int i = 0; i < controller.GetEntryCount(); ++i) {
NavigationEntryImpl::TreeNode* root =
controller.GetEntryAtIndex(i)->root_node();
ASSERT_EQ(1U, root->children.size());
names.insert(root->children[0]->frame_entry->frame_unique_name());
}
EXPECT_THAT(names, SizeIs(1)) << "Mismatched names for subframe!";
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, PostTargetSubFrame) {
GURL main_url(
embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(1u, root->child_count());
EXPECT_NE(root->current_frame_host()->GetSiteInstance(),
root->child_at(0)->current_frame_host()->GetSiteInstance());
GURL form_url(embedded_test_server()->GetURL("/echoall"));
TestNavigationObserver form_post_observer(shell()->web_contents(), 1);
EXPECT_TRUE(ExecJs(shell()->web_contents(), JsReplace(R"(
var form = document.createElement('form');
// POST form submission to /echoall.
form.setAttribute("method", "POST");
form.setAttribute("action", $1);
// Target the OOPIF.
form.setAttribute("target", "child-name-0");
// Add some POST data: "my_token=my_value";
var input = document.createElement("input");
input.setAttribute("type", "hidden");
input.setAttribute("name", "my_token");
input.setAttribute("value", "my_value");
form.appendChild(input);
// Submit the form.
document.body.appendChild(form);
form.submit();
)",
form_url)));
form_post_observer.Wait();
NavigationEntryImpl* entry = static_cast<NavigationEntryImpl*>(
shell()->web_contents()->GetController().GetLastCommittedEntry());
EXPECT_FALSE(entry->is_renderer_initiated());
EXPECT_EQ("my_token=my_value\n",
EvalJs(root->child_at(0),
"document.getElementsByTagName('pre')[0].innerText;"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
PostTargetsMainFrameFromOOPIF) {
GURL main_url(
embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(1u, root->child_count());
EXPECT_NE(root->current_frame_host()->GetSiteInstance(),
root->child_at(0)->current_frame_host()->GetSiteInstance());
GURL form_url(embedded_test_server()->GetURL("/echoall"));
TestNavigationObserver form_post_observer(web_contents());
EXPECT_TRUE(
ExecJs(root->child_at(0)->current_frame_host(), JsReplace(R"(
var form = document.createElement('form');
// POST form submission to /echoall.
form.setAttribute("method", "POST");
form.setAttribute("action", $1);
// Target the parent.
form.setAttribute("target", "_parent");
// Add some POST data: "my_token=my_value";
var input = document.createElement("input");
input.setAttribute("type", "hidden");
input.setAttribute("name", "my_token");
input.setAttribute("value", "my_value");
form.appendChild(input);
// Submit the form.
document.body.appendChild(form);
form.submit();
)",
form_url)));
form_post_observer.Wait();
NavigationEntryImpl* entry = static_cast<NavigationEntryImpl*>(
web_contents()->GetController().GetLastCommittedEntry());
EXPECT_EQ("POST", entry->root_node()->frame_entry->method());
EXPECT_EQ("my_token=my_value\n",
EvalJs(root, "document.getElementsByTagName('pre')[0].innerText"));
web_contents()->GetController().Reload(ReloadType::NORMAL,
false );
EXPECT_TRUE(WaitForLoadStop(web_contents()));
EXPECT_EQ("my_token=my_value\n",
EvalJs(root, "document.getElementsByTagName('pre')[0].innerText"));
}
IN_PROC_BROWSER_TEST_P(
SitePerProcessBrowserTest,
DISABLED_CrossProcessMainFrameNavigationDoesNotOverwriteHistory) {
GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title2.html"));
EXPECT_TRUE(NavigateToURL(shell(), foo_url));
OpenPopup(shell(), GURL(url::kAboutBlankURL), "foo");
EXPECT_TRUE(NavigateToURLFromRenderer(shell(), bar_url));
EXPECT_TRUE(NavigateToURLFromRenderer(shell(), foo_url));
EXPECT_EQ(3, web_contents()->GetController().GetEntryCount());
{
TestNavigationObserver back_observer(web_contents());
web_contents()->GetController().GoBack();
back_observer.Wait();
}
EXPECT_EQ(bar_url,
web_contents()->GetPrimaryMainFrame()->GetLastCommittedURL());
{
TestNavigationObserver back_observer(web_contents());
web_contents()->GetController().GoBack();
back_observer.Wait();
}
EXPECT_EQ(foo_url,
web_contents()->GetPrimaryMainFrame()->GetLastCommittedURL());
}
#if BUILDFLAG(IS_POSIX)
#define MAYBE_CrossProcessInertSubframe DISABLED_CrossProcessInertSubframe
#else
#define MAYBE_CrossProcessInertSubframe CrossProcessInertSubframe
#endif
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
MAYBE_CrossProcessInertSubframe) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b,b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(2U, root->child_count());
FrameTreeNode* iframe_node = root->child_at(0);
EXPECT_TRUE(ExecJs(
iframe_node,
"document.head.innerHTML = '';"
"document.body.innerHTML = '<input id=\"text1\"> <input id=\"text2\">';"
"text1.focus();"));
EXPECT_TRUE(ExecJs(root,
"let dialog = "
"document.body.appendChild(document.createElement('"
"dialog'));"
"dialog.innerHTML = 'Modal dialog <input>';"
"dialog.showModal();"));
base::RunLoop().RunUntilIdle();
RenderFrameProxyHost* root_proxy =
iframe_node->render_manager()->GetProxyToParent();
EXPECT_TRUE(root_proxy->IsInertForTesting());
std::string focused_element;
EXPECT_EQ("text2", EvalJs(iframe_node,
"new Promise(resolve => {"
" window.setTimeout(() => {"
" text2.focus();"
" resolve(document.activeElement.id);"
" }, 0);"
"});"));
GURL site_url(embedded_test_server()->GetURL("c.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(iframe_node, site_url));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(ExecJs(
iframe_node,
"document.head.innerHTML = '';"
"document.body.innerHTML = '<input id=\"text1\"> <input id=\"text2\">';"
"text1.focus();"));
EXPECT_EQ("text2", EvalJs(iframe_node,
"text2.focus();"
"document.activeElement.id;"));
GURL same_site_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(iframe_node, same_site_url));
EXPECT_TRUE(ExecJs(
iframe_node,
"document.head.innerHTML = '';"
"document.body.innerHTML = '<input id=\"text1\"> <input id=\"text2\">';"
"text1.focus();"));
EXPECT_EQ("text2", EvalJs(iframe_node,
"text2.focus();"
"document.activeElement.id;"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
CrossProcessIsInertPropagation) {
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kEnableBlinkFeatures, "InertAttribute");
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b(c))"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* frame_a =
static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
ASSERT_EQ(1U, frame_a->child_count());
FrameTreeNode* frame_b = frame_a->child_at(0);
ASSERT_EQ(1U, frame_b->child_count());
FrameTreeNode* frame_c = frame_b->child_at(0);
RenderFrameProxyHost* proxy_b = frame_b->render_manager()->GetProxyToParent();
RenderFrameProxyHost* proxy_c = frame_c->render_manager()->GetProxyToParent();
auto waitForInertPropagated = [&]() {
for (FrameTreeNode* frame : {frame_a, frame_b, frame_c})
ExecuteScriptAsync(frame, "document.body.offsetLeft");
for (FrameTreeNode* frame : {frame_a, frame_b, frame_c})
EXPECT_TRUE(ExecJs(frame, "'Done'"));
};
waitForInertPropagated();
EXPECT_FALSE(proxy_b->IsInertForTesting());
EXPECT_FALSE(proxy_c->IsInertForTesting());
EXPECT_TRUE(ExecJs(frame_a, "document.body.inert = true;"));
waitForInertPropagated();
EXPECT_TRUE(proxy_b->IsInertForTesting());
EXPECT_TRUE(proxy_c->IsInertForTesting());
EXPECT_TRUE(ExecJs(frame_a, "document.body.inert = false;"));
waitForInertPropagated();
EXPECT_FALSE(proxy_b->IsInertForTesting());
EXPECT_FALSE(proxy_c->IsInertForTesting());
EXPECT_TRUE(ExecJs(frame_b, "document.body.inert = true;"));
waitForInertPropagated();
EXPECT_FALSE(proxy_b->IsInertForTesting());
EXPECT_TRUE(proxy_c->IsInertForTesting());
EXPECT_TRUE(ExecJs(frame_a, "document.body.inert = true;"));
waitForInertPropagated();
EXPECT_TRUE(proxy_b->IsInertForTesting());
EXPECT_TRUE(proxy_c->IsInertForTesting());
EXPECT_TRUE(ExecJs(frame_b, "document.body.inert = false;"));
waitForInertPropagated();
EXPECT_TRUE(proxy_b->IsInertForTesting());
EXPECT_TRUE(proxy_c->IsInertForTesting());
EXPECT_TRUE(ExecJs(frame_a, "document.body.inert = false;"));
waitForInertPropagated();
EXPECT_FALSE(proxy_b->IsInertForTesting());
EXPECT_FALSE(proxy_c->IsInertForTesting());
EXPECT_TRUE(ExecJs(frame_a, "document.body.inert = true;"));
EXPECT_TRUE(ExecJs(frame_b, "document.body.inert = true;"));
waitForInertPropagated();
EXPECT_TRUE(proxy_b->IsInertForTesting());
EXPECT_TRUE(proxy_c->IsInertForTesting());
EXPECT_TRUE(ExecJs(frame_a, "document.body.inert = false;"));
waitForInertPropagated();
EXPECT_FALSE(proxy_b->IsInertForTesting());
EXPECT_TRUE(proxy_c->IsInertForTesting());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
MainFrameProcessReuseWhenOverLimit) {
RenderProcessHost::SetMaxRendererProcessCount(1);
GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
ASSERT_TRUE(NavigateToURL(shell(), url_a));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html"));
Shell* new_shell = CreateBrowser();
EXPECT_TRUE(NavigateToURL(new_shell, url_b));
FrameTreeNode* new_shell_root =
static_cast<WebContentsImpl*>(new_shell->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_NE(root->current_frame_host()->GetProcess(),
new_shell_root->current_frame_host()->GetProcess());
EXPECT_TRUE(NavigateToURL(new_shell, url_a));
EXPECT_EQ(root->current_frame_host()->GetProcess(),
new_shell_root->current_frame_host()->GetProcess());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
SubframeProcessReuseWhenOverLimit) {
RenderProcessHost::SetMaxRendererProcessCount(1);
GURL first_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b,b(c))"));
ASSERT_TRUE(NavigateToURL(shell(), first_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_NE(root->current_frame_host()->GetProcess(),
root->child_at(0)->current_frame_host()->GetProcess());
EXPECT_NE(root->current_frame_host()->GetProcess(),
root->child_at(1)->current_frame_host()->GetProcess());
EXPECT_NE(root->current_frame_host()->GetProcess(),
root->child_at(1)->child_at(0)->current_frame_host()->GetProcess());
EXPECT_NE(root->child_at(1)->current_frame_host()->GetProcess(),
root->child_at(1)->child_at(0)->current_frame_host()->GetProcess());
EXPECT_EQ(root->child_at(0)->current_frame_host()->GetProcess(),
root->child_at(1)->current_frame_host()->GetProcess());
Shell* new_shell = CreateBrowser();
GURL new_shell_url(embedded_test_server()->GetURL(
"d.com", "/cross_site_iframe_factory.html?d(a(b))"));
ASSERT_TRUE(NavigateToURL(new_shell, new_shell_url));
FrameTreeNode* new_shell_root =
static_cast<WebContentsImpl*>(new_shell->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_NE(root->current_frame_host()->GetProcess(),
new_shell_root->current_frame_host()->GetProcess());
EXPECT_NE(root->child_at(0)->current_frame_host()->GetProcess(),
new_shell_root->current_frame_host()->GetProcess());
EXPECT_NE(root->child_at(1)->child_at(0)->current_frame_host()->GetProcess(),
new_shell_root->current_frame_host()->GetProcess());
EXPECT_EQ(root->current_frame_host()->GetProcess(),
new_shell_root->child_at(0)->current_frame_host()->GetProcess());
EXPECT_EQ(root->child_at(0)->current_frame_host()->GetProcess(),
new_shell_root->child_at(0)
->child_at(0)
->current_frame_host()
->GetProcess());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
TwoCrossSitePendingNavigationsAndMainFrameWins) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child = root->child_at(0);
GURL new_url_1(embedded_test_server()->GetURL("b.com", "/title1.html"));
GURL new_url_2(embedded_test_server()->GetURL("b.com", "/title2.html"));
TestNavigationManager manager1(web_contents(), new_url_1);
TestNavigationManager manager2(web_contents(), new_url_2);
auto script = JsReplace("location = $1; frames[0].location = $2;", new_url_1,
new_url_2);
EXPECT_TRUE(ExecJs(web_contents(), script));
ASSERT_TRUE(manager1.WaitForRequestStart());
RenderFrameHostImpl* root_speculative_rfh =
root->render_manager()->speculative_frame_host();
EXPECT_TRUE(root_speculative_rfh);
scoped_refptr<SiteInstanceImpl> b_root_site_instance(
root_speculative_rfh->GetSiteInstance());
RenderFrameProxyHost* root_proxy =
root->current_frame_host()
->browsing_context_state()
->GetRenderFrameProxyHost(b_root_site_instance->group());
EXPECT_TRUE(root_proxy);
EXPECT_TRUE(root_proxy->is_render_frame_proxy_live());
ASSERT_TRUE(manager2.WaitForRequestStart());
RenderFrameHostImpl* subframe_speculative_rfh =
child->render_manager()->speculative_frame_host();
EXPECT_TRUE(child->render_manager()->speculative_frame_host());
scoped_refptr<SiteInstanceImpl> b_subframe_site_instance(
subframe_speculative_rfh->GetSiteInstance());
RenderFrameProxyHost* child_proxy =
child->current_frame_host()
->browsing_context_state()
->GetRenderFrameProxyHost(b_subframe_site_instance->group());
EXPECT_TRUE(child_proxy);
EXPECT_TRUE(child_proxy->is_render_frame_proxy_live());
ASSERT_TRUE(manager1.WaitForNavigationFinished());
EXPECT_TRUE(b_root_site_instance->GetProcess()->IsInitializedAndNotDead());
EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
EXPECT_EQ(root_speculative_rfh, root->current_frame_host());
EXPECT_EQ(new_url_1, root->current_frame_host()->GetLastCommittedURL());
ASSERT_TRUE(manager2.WaitForNavigationFinished());
EXPECT_EQ(0U, root->child_count());
EXPECT_EQ(0, EvalJs(web_contents(), "frames.length;"));
EXPECT_FALSE(
root->current_frame_host()
->browsing_context_state()
->GetRenderFrameProxyHost(b_subframe_site_instance->group()));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
TwoCrossSitePendingNavigationsAndSubframeWins) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a,a)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child = root->child_at(0);
FrameTreeNode* child2 = root->child_at(1);
EXPECT_TRUE(ExecJs(root->current_frame_host(),
"window.addEventListener('message', function(event) {\n"
" event.source.postMessage(event.data + '-reply', '*');\n"
"});"));
EXPECT_TRUE(ExecJs(
child2->current_frame_host(),
"window.addEventListener('message', function(event) {\n"
" event.source.postMessage(event.data + '-subframe-reply', '*');\n"
"});"));
GURL new_url_1(embedded_test_server()->GetURL("b.com", "/title1.html"));
TestNavigationManager manager1(web_contents(), new_url_1);
EXPECT_TRUE(ExecJs(web_contents(), JsReplace("location = $1", new_url_1)));
ASSERT_TRUE(manager1.WaitForRequestStart());
EXPECT_EQ(
" Site A (B speculative) -- proxies for B\n"
" |--Site A\n"
" +--Site A\n"
"Where A = http://a.com/\n"
" B = http://b.com/",
DepictFrameTree(root));
GURL new_url_2(embedded_test_server()->GetURL("b.com", "/title2.html"));
TestNavigationManager manager2(web_contents(), new_url_2);
EXPECT_TRUE(
ExecJs(web_contents(), JsReplace("frames[0].location = $1", new_url_2)));
ASSERT_TRUE(manager2.WaitForRequestStart());
RenderFrameHostImpl* child_speculative_rfh =
child->render_manager()->speculative_frame_host();
EXPECT_TRUE(child_speculative_rfh);
scoped_refptr<SiteInstanceImpl> b_site_instance(
child_speculative_rfh->GetSiteInstance());
if (CanCrossSiteNavigationsProactivelySwapBrowsingInstances()) {
EXPECT_EQ(
" Site A (B speculative) -- proxies for B C\n"
" |--Site A (C speculative) -- proxies for C\n"
" +--Site A ------- proxies for C\n"
"Where A = http://a.com/\n"
" B = http://b.com/\n"
" C = http://b.com/",
DepictFrameTree(root));
} else {
EXPECT_EQ(
" Site A (B speculative) -- proxies for B\n"
" |--Site A (B speculative) -- proxies for B\n"
" +--Site A ------- proxies for B\n"
"Where A = http://a.com/\n"
" B = http://b.com/",
DepictFrameTree(root));
}
ASSERT_TRUE(manager2.WaitForNavigationFinished());
EXPECT_TRUE(b_site_instance->GetProcess()->IsInitializedAndNotDead());
ASSERT_EQ(2U, root->child_count());
EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive());
EXPECT_EQ(child_speculative_rfh, child->current_frame_host());
EXPECT_EQ(new_url_2, child->current_frame_host()->GetLastCommittedURL());
if (CanCrossSiteNavigationsProactivelySwapBrowsingInstances()) {
EXPECT_EQ(
" Site A (B speculative) -- proxies for B C\n"
" |--Site C ------- proxies for A\n"
" +--Site A ------- proxies for C\n"
"Where A = http://a.com/\n"
" B = http://b.com/\n"
" C = http://b.com/",
DepictFrameTree(root));
} else {
EXPECT_EQ(
" Site A (B speculative) -- proxies for B\n"
" |--Site B ------- proxies for A\n"
" +--Site A ------- proxies for B\n"
"Where A = http://a.com/\n"
" B = http://b.com/",
DepictFrameTree(root));
}
EXPECT_TRUE(
ExecJs(child->current_frame_host(), WaitForMessageScript("event.data")));
EXPECT_TRUE(ExecJs(child, "parent.postMessage('root-ping', '*')"));
EXPECT_EQ("root-ping-reply",
EvalJs(child->current_frame_host(), "onMessagePromise"));
EXPECT_TRUE(
ExecJs(child->current_frame_host(), WaitForMessageScript("event.data")));
EXPECT_TRUE(
ExecJs(child, "parent.frames[1].postMessage('sibling-ping', '*')"));
EXPECT_EQ("sibling-ping-subframe-reply",
EvalJs(child->current_frame_host(), "onMessagePromise"));
root->navigator().CancelNavigation(root, NavigationDiscardReason::kCancelled);
EXPECT_FALSE(root->render_manager()->speculative_frame_host());
EXPECT_TRUE(
ExecJs(child->current_frame_host(), WaitForMessageScript("event.data")));
EXPECT_TRUE(ExecJs(child, "parent.postMessage('root-ping', '*')"));
EXPECT_EQ("root-ping-reply",
EvalJs(child->current_frame_host(), "onMessagePromise"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
TwoCrossSitePendingNavigationsWithOpener) {
GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_TRUE(ExecJs(web_contents(),
"window.addEventListener('message', function(event) {\n"
" event.source.postMessage(event.data + '-reply', '*');\n"
"});"));
Shell* popup_shell =
OpenPopup(shell()->web_contents(), GURL(url::kAboutBlankURL), "popup");
GURL new_url_1(embedded_test_server()->GetURL("b.com", "/title1.html"));
TestNavigationManager manager(web_contents(), new_url_1);
EXPECT_TRUE(ExecJs(web_contents(), JsReplace("location = $1", new_url_1)));
ASSERT_TRUE(manager.WaitForRequestStart());
GURL new_url_2(embedded_test_server()->GetURL("b.com", "/title2.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(popup_shell, new_url_2));
RenderFrameHostImpl* speculative_rfh =
root->render_manager()->speculative_frame_host();
EXPECT_TRUE(speculative_rfh);
scoped_refptr<SiteInstanceImpl> b_site_instance(
speculative_rfh->GetSiteInstance());
RenderFrameProxyHost* proxy =
root->current_frame_host()
->browsing_context_state()
->GetRenderFrameProxyHost(b_site_instance->group());
EXPECT_TRUE(proxy);
EXPECT_TRUE(proxy->is_render_frame_proxy_live());
EXPECT_TRUE(
ExecJs(popup_shell->web_contents(), WaitForMessageScript("event.data")));
EXPECT_TRUE(ExecJs(popup_shell->web_contents(),
"opener.postMessage('opener-ping', '*');"));
EXPECT_EQ("opener-ping-reply",
EvalJs(popup_shell->web_contents(), "onMessagePromise"));
root->navigator().CancelNavigation(root, NavigationDiscardReason::kCancelled);
EXPECT_FALSE(root->render_manager()->speculative_frame_host());
EXPECT_TRUE(
ExecJs(popup_shell->web_contents(), WaitForMessageScript("event.data")));
EXPECT_TRUE(ExecJs(popup_shell->web_contents(),
"opener.postMessage('opener-ping', '*')"));
EXPECT_EQ("opener-ping-reply",
EvalJs(popup_shell->web_contents(), "onMessagePromise"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
DetachSpeculativeRenderFrameHost) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
GURL cross_site_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
TestNavigationManager nav_manager(shell()->web_contents(), cross_site_url);
BeginNavigateIframeToURL(web_contents(), "child-0", cross_site_url);
ASSERT_TRUE(nav_manager.WaitForRequestStart());
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
RenderFrameHostImpl* speculative_rfh = root->current_frame_host()
->child_at(0)
->render_manager()
->speculative_frame_host();
EXPECT_TRUE(speculative_rfh);
speculative_rfh->Detach();
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
CancelNavigationAfterReadyToCommit) {
class NavigationCanceller : public WebContentsObserver {
public:
NavigationCanceller(WebContents* web_contents,
RenderFrameHost& requesting_rfh)
: WebContentsObserver(web_contents), requesting_rfh_(requesting_rfh) {}
void ReadyToCommitNavigation(NavigationHandle* navigation_handle) override {
ExecuteScriptAsync(&*requesting_rfh_, "window.stop()");
}
private:
const raw_ref<RenderFrameHost, DanglingUntriaged> requesting_rfh_;
};
GURL url1(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
EXPECT_TRUE(NavigateToURL(web_contents(), url1));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
GURL url2(embedded_test_server()->GetURL("a.com", "/title1.html"));
TestNavigationManager nav_manager(web_contents(), url2);
FrameTreeNode* first_child = root->child_at(0);
EXPECT_TRUE(BeginNavigateToURLFromRenderer(
first_child->render_manager()->current_frame_host(), url2));
EXPECT_TRUE(nav_manager.WaitForResponse());
bool using_speculative_rfh =
!!first_child->render_manager()->speculative_frame_host();
NavigationCanceller canceller(
web_contents(), *first_child->render_manager()->current_frame_host());
ASSERT_TRUE(nav_manager.WaitForNavigationFinished());
EXPECT_EQ(using_speculative_rfh, nav_manager.was_committed());
}
namespace {
class AssertNoReadyToCommitNavigationCalls : public WebContentsObserver {
public:
explicit AssertNoReadyToCommitNavigationCalls(WebContents* contents)
: WebContentsObserver(contents) {}
private:
void ReadyToCommitNavigation(NavigationHandle* handle) override {
ASSERT_TRUE(false);
}
};
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
ObjectTagSameSiteNavigationWithHTTPError) {
GURL url1(embedded_test_server()->GetURL("a.com", "/object-frame.html"));
EXPECT_TRUE(NavigateToURL(web_contents(), url1));
EXPECT_EQ(1, EvalJs(web_contents(), "window.length"));
EXPECT_EQ("", EvalJs(web_contents(), "document.body.innerText"));
AssertNoReadyToCommitNavigationCalls asserter(web_contents());
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
GURL url2(embedded_test_server()->GetURL("a.com", "/page404.html"));
TestNavigationManager nav_manager(web_contents(), url2);
FrameTreeNode* first_child = root->child_at(0);
EXPECT_TRUE(BeginNavigateToURLFromRenderer(
first_child->render_manager()->current_frame_host(), url2));
const bool using_speculative_rfh =
!!first_child->render_manager()->speculative_frame_host();
EXPECT_EQ(using_speculative_rfh,
GetRenderDocumentLevel() >= RenderDocumentLevel::kSubframe);
ASSERT_TRUE(nav_manager.WaitForNavigationFinished());
EXPECT_FALSE(nav_manager.was_committed());
EXPECT_FALSE(nav_manager.was_successful());
EXPECT_EQ(1, EvalJs(web_contents(), "window.length"));
EXPECT_EQ("fallback", EvalJs(web_contents(), "document.body.innerText"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
ObjectTagCrossSiteNavigationWithHTTPError) {
GURL url1(embedded_test_server()->GetURL("a.com", "/object-frame.html"));
EXPECT_TRUE(NavigateToURL(web_contents(), url1));
EXPECT_EQ(1, EvalJs(web_contents(), "window.length"));
EXPECT_EQ("", EvalJs(web_contents(), "document.body.innerText"));
AssertNoReadyToCommitNavigationCalls asserter(web_contents());
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
GURL url2(embedded_test_server()->GetURL("b.com", "/page404.html"));
TestNavigationManager nav_manager(web_contents(), url2);
FrameTreeNode* first_child = root->child_at(0);
EXPECT_TRUE(BeginNavigateToURLFromRenderer(
first_child->render_manager()->current_frame_host(), url2));
EXPECT_TRUE(first_child->render_manager()->speculative_frame_host());
ASSERT_TRUE(nav_manager.WaitForNavigationFinished());
EXPECT_FALSE(nav_manager.was_committed());
EXPECT_FALSE(nav_manager.was_successful());
EXPECT_EQ(1, EvalJs(web_contents(), "window.length"));
EXPECT_EQ("fallback", EvalJs(web_contents(), "document.body.innerText"));
}
IN_PROC_BROWSER_TEST_P(
SitePerProcessBrowserTest,
ObjectTagSameSiteNavigationWithHTTPErrorAndFailedBodyLoad) {
GURL url1(embedded_test_server()->GetURL("a.com", "/object-frame.html"));
EXPECT_TRUE(NavigateToURL(web_contents(), url1));
EXPECT_EQ(1, EvalJs(web_contents(), "window.length"));
EXPECT_EQ("", EvalJs(web_contents(), "document.body.innerText"));
TestNavigationThrottleInserter navigation_throttle_inserter(
web_contents(),
base::BindRepeating(
[](NavigationHandle* handle) -> std::unique_ptr<NavigationThrottle> {
auto throttle = std::make_unique<TestNavigationThrottle>(handle);
throttle->SetCallback(
TestNavigationThrottle::WILL_PROCESS_RESPONSE,
base::BindLambdaForTesting([handle]() {
mojo::Remote<network::mojom::URLLoaderClient>
remote_to_be_dropped;
auto* request = static_cast<NavigationRequest*>(handle);
request->mutable_url_loader_client_endpoints_for_testing()
->url_loader_client =
remote_to_be_dropped.BindNewPipeAndPassReceiver();
}));
return throttle;
}));
AssertNoReadyToCommitNavigationCalls asserter(web_contents());
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
GURL url2(embedded_test_server()->GetURL("a.com", "/page404.html"));
TestNavigationManager nav_manager(web_contents(), url2);
FrameTreeNode* first_child = root->child_at(0);
EXPECT_TRUE(BeginNavigateToURLFromRenderer(
first_child->render_manager()->current_frame_host(), url2));
const bool using_speculative_rfh =
!!first_child->render_manager()->speculative_frame_host();
EXPECT_EQ(using_speculative_rfh,
GetRenderDocumentLevel() >= RenderDocumentLevel::kSubframe);
ASSERT_TRUE(nav_manager.WaitForNavigationFinished());
EXPECT_FALSE(nav_manager.was_committed());
EXPECT_FALSE(nav_manager.was_successful());
EXPECT_EQ(1, EvalJs(web_contents(), "window.length"));
EXPECT_EQ("fallback", EvalJs(web_contents(), "document.body.innerText"));
EXPECT_FALSE(first_child->navigation_request());
}
IN_PROC_BROWSER_TEST_P(
SitePerProcessBrowserTest,
ObjectTagCrossSiteNavigationWithHTTPErrorAndFailedBodyLoad) {
GURL url1(embedded_test_server()->GetURL("a.com", "/object-frame.html"));
EXPECT_TRUE(NavigateToURL(web_contents(), url1));
EXPECT_EQ(1, EvalJs(web_contents(), "window.length"));
EXPECT_EQ("", EvalJs(web_contents(), "document.body.innerText"));
TestNavigationThrottleInserter navigation_throttle_inserter(
web_contents(),
base::BindRepeating(
[](NavigationHandle* handle) -> std::unique_ptr<NavigationThrottle> {
auto throttle = std::make_unique<TestNavigationThrottle>(handle);
throttle->SetCallback(
TestNavigationThrottle::WILL_PROCESS_RESPONSE,
base::BindLambdaForTesting([handle]() {
mojo::Remote<network::mojom::URLLoaderClient>
remote_to_be_dropped;
auto* request = static_cast<NavigationRequest*>(handle);
request->mutable_url_loader_client_endpoints_for_testing()
->url_loader_client =
remote_to_be_dropped.BindNewPipeAndPassReceiver();
}));
return throttle;
}));
AssertNoReadyToCommitNavigationCalls asserter(web_contents());
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
GURL url2(embedded_test_server()->GetURL("b.com", "/page404.html"));
TestNavigationManager nav_manager(web_contents(), url2);
FrameTreeNode* first_child = root->child_at(0);
EXPECT_TRUE(BeginNavigateToURLFromRenderer(
first_child->render_manager()->current_frame_host(), url2));
EXPECT_TRUE(first_child->render_manager()->speculative_frame_host());
ASSERT_TRUE(nav_manager.WaitForNavigationFinished());
EXPECT_FALSE(nav_manager.was_committed());
EXPECT_FALSE(nav_manager.was_successful());
EXPECT_EQ(1, EvalJs(web_contents(), "window.length"));
EXPECT_EQ("fallback", EvalJs(web_contents(), "document.body.innerText"));
EXPECT_FALSE(first_child->navigation_request());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
ObjectTagSameSiteNavigationWithNetworkError) {
GURL url1(embedded_test_server()->GetURL("a.com", "/object-frame.html"));
EXPECT_TRUE(NavigateToURL(web_contents(), url1));
AssertNoReadyToCommitNavigationCalls asserter(web_contents());
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
GURL error_url(embedded_test_server()->GetURL("a.com", "/empty.html"));
std::unique_ptr<URLLoaderInterceptor> interceptor =
URLLoaderInterceptor::SetupRequestFailForURL(error_url,
net::ERR_CONNECTION_REFUSED);
TestNavigationManager nav_manager(web_contents(), error_url);
FrameTreeNode* first_child = root->child_at(0);
EXPECT_TRUE(BeginNavigateToURLFromRenderer(
first_child->render_manager()->current_frame_host(), error_url));
const bool using_speculative_rfh =
!!first_child->render_manager()->speculative_frame_host();
EXPECT_EQ(using_speculative_rfh,
GetRenderDocumentLevel() >= RenderDocumentLevel::kSubframe);
EXPECT_FALSE(nav_manager.WaitForResponse());
ASSERT_TRUE(nav_manager.WaitForNavigationFinished());
EXPECT_FALSE(nav_manager.was_committed());
EXPECT_EQ(nullptr, first_child->render_manager()->speculative_frame_host());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
ObjectTagCrossSiteNavigationWithNetworkError) {
GURL url1(embedded_test_server()->GetURL("a.com", "/object-frame.html"));
EXPECT_TRUE(NavigateToURL(web_contents(), url1));
AssertNoReadyToCommitNavigationCalls asserter(web_contents());
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
GURL error_url(embedded_test_server()->GetURL("b.com", "/empty.html"));
std::unique_ptr<URLLoaderInterceptor> interceptor =
URLLoaderInterceptor::SetupRequestFailForURL(error_url,
net::ERR_CONNECTION_REFUSED);
TestNavigationManager nav_manager(web_contents(), error_url);
FrameTreeNode* first_child = root->child_at(0);
EXPECT_TRUE(BeginNavigateToURLFromRenderer(
first_child->render_manager()->current_frame_host(), error_url));
EXPECT_TRUE(first_child->render_manager()->speculative_frame_host());
EXPECT_FALSE(nav_manager.WaitForResponse());
ASSERT_TRUE(nav_manager.WaitForNavigationFinished());
EXPECT_FALSE(nav_manager.was_committed());
EXPECT_EQ(nullptr, first_child->render_manager()->speculative_frame_host());
}
class SitePerProcessBrowserTestWithLeakDetector
: public SitePerProcessBrowserTest {
public:
void SetUpCommandLine(base::CommandLine* command_line) override {
SitePerProcessBrowserTest::SetUpCommandLine(command_line);
command_line->AppendSwitchASCII(blink::switches::kJavaScriptFlags,
"--expose-gc");
}
};
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTestWithLeakDetector,
CloseWebContentsWithSpeculativeRenderFrameHost) {
const GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
ASSERT_TRUE(NavigateToURL(web_contents(), url1));
Shell* new_shell =
OpenPopup(web_contents(),
embedded_test_server()->GetURL("b.com", "/title1.html"), "");
ASSERT_TRUE(new_shell);
mojo::Remote<blink::mojom::LeakDetector> leak_detector_remote;
new_shell->web_contents()->GetPrimaryMainFrame()->GetProcess()->BindReceiver(
leak_detector_remote.BindNewPipeAndPassReceiver());
blink::mojom::LeakDetectorAsyncWaiter leak_detector(
leak_detector_remote.get());
{
blink::mojom::LeakDetectionResultPtr result;
leak_detector.PerformLeakDetection(&result);
EXPECT_EQ(1u, result->number_of_live_documents);
EXPECT_EQ(2u, result->number_of_live_frames);
}
const GURL url2(embedded_test_server()->GetURL("b.com", "/title1.html"));
TestNavigationManager nav_manager(web_contents(), url2);
ASSERT_TRUE(BeginNavigateToURLFromRenderer(web_contents(), url2));
ASSERT_TRUE(nav_manager.WaitForResponse());
{
blink::mojom::LeakDetectionResultPtr result;
leak_detector.PerformLeakDetection(&result);
EXPECT_EQ(2u, result->number_of_live_documents);
EXPECT_EQ(3u, result->number_of_live_frames);
}
shell()->Close();
EXPECT_TRUE(ExecJs(new_shell, ""));
{
blink::mojom::LeakDetectionResultPtr result;
leak_detector.PerformLeakDetection(&result);
EXPECT_EQ(1u, result->number_of_live_documents);
EXPECT_EQ(1u, result->number_of_live_frames);
}
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTestWithLeakDetector,
DetachFrameWithSpeculativeRenderFrameHost) {
const GURL url1(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
ASSERT_TRUE(NavigateToURL(web_contents(), url1));
Shell* new_shell =
OpenPopup(web_contents(),
embedded_test_server()->GetURL("b.com", "/title1.html"), "");
ASSERT_TRUE(new_shell);
mojo::Remote<blink::mojom::LeakDetector> leak_detector_remote;
new_shell->web_contents()->GetPrimaryMainFrame()->GetProcess()->BindReceiver(
leak_detector_remote.BindNewPipeAndPassReceiver());
blink::mojom::LeakDetectorAsyncWaiter leak_detector(
leak_detector_remote.get());
{
blink::mojom::LeakDetectionResultPtr result;
leak_detector.PerformLeakDetection(&result);
EXPECT_EQ(1u, result->number_of_live_documents);
EXPECT_EQ(3u, result->number_of_live_frames);
}
const GURL url2(embedded_test_server()->GetURL("b.com", "/title1.html"));
TestNavigationManager nav_manager(web_contents(), url2);
ASSERT_TRUE(BeginNavigateToURLFromRenderer(web_contents()
->GetPrimaryFrameTree()
.root()
->current_frame_host()
->child_at(0),
url2));
ASSERT_TRUE(nav_manager.WaitForResponse());
{
blink::mojom::LeakDetectionResultPtr result;
leak_detector.PerformLeakDetection(&result);
EXPECT_EQ(2u, result->number_of_live_documents);
EXPECT_EQ(4u, result->number_of_live_frames);
}
EXPECT_TRUE(
ExecJs(web_contents(), "document.querySelector('iframe').remove()"));
EXPECT_TRUE(ExecJs(new_shell, ""));
{
blink::mojom::LeakDetectionResultPtr result;
leak_detector.PerformLeakDetection(&result);
EXPECT_EQ(1u, result->number_of_live_documents);
EXPECT_EQ(2u, result->number_of_live_frames);
}
}
#if BUILDFLAG(IS_ANDROID)
namespace {
class MockEventHandlerAndroid : public ui::EventHandlerAndroid {
public:
bool OnTouchEvent(const ui::MotionEventAndroid& event) override {
did_receive_event_ = true;
return true;
}
bool did_receive_event() { return did_receive_event_; }
private:
bool did_receive_event_ = false;
};
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
SpeculativeRenderFrameHostDoesNotReceiveInput) {
GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url1));
RenderWidgetHostViewAndroid* rwhva =
static_cast<RenderWidgetHostViewAndroid*>(
shell()->web_contents()->GetRenderWidgetHostView());
ui::ViewAndroid* rwhva_native_view = rwhva->GetNativeView();
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
GURL url2(embedded_test_server()->GetURL("b.com", "/title2.html"));
TestNavigationManager nav_manager(web_contents(), url2);
shell()->LoadURL(url2);
ASSERT_TRUE(nav_manager.WaitForRequestStart());
RenderFrameHostImpl* root_speculative_rfh =
root->render_manager()->speculative_frame_host();
EXPECT_TRUE(root_speculative_rfh);
RenderWidgetHostViewAndroid* rwhv_speculative =
static_cast<RenderWidgetHostViewAndroid*>(
root_speculative_rfh->GetView());
ui::ViewAndroid* rwhv_speculative_native_view =
rwhv_speculative->GetNativeView();
ui::ViewAndroid* root_view = web_contents()->GetView()->GetNativeView();
EXPECT_TRUE(root_view);
MockEventHandlerAndroid mock_handler;
rwhva_native_view->set_event_handler(&mock_handler);
MockEventHandlerAndroid mock_handler_speculative;
rwhv_speculative_native_view->set_event_handler(&mock_handler_speculative);
root_view->set_event_handler(nullptr);
auto size = root_view->GetSize();
float x = size.width() / 2;
float y = size.height() / 2;
ui::MotionEventAndroid::Pointer pointer0(0, x, y, 0, 0, 0, 0, 0);
ui::MotionEventAndroid::Pointer pointer1(0, 0, 0, 0, 0, 0, 0, 0);
ui::MotionEventAndroid event(nullptr, nullptr, 1.f / root_view->GetDipScale(),
0.f, 0.f, 0.f, base::TimeTicks(), 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, false, &pointer0, &pointer1);
root_view->OnTouchEventForTesting(event);
EXPECT_TRUE(mock_handler.did_receive_event());
EXPECT_FALSE(mock_handler_speculative.did_receive_event());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, TestChildProcessImportance) {
web_contents()->SetPrimaryMainFrameImportance(
ChildProcessImportance::MODERATE);
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
ASSERT_EQ(1u, root->child_count());
FrameTreeNode* child = root->child_at(0);
EXPECT_EQ(ChildProcessImportance::MODERATE,
root->current_frame_host()->GetProcess()->GetEffectiveImportance());
EXPECT_EQ(
ChildProcessImportance::NORMAL,
child->current_frame_host()->GetProcess()->GetEffectiveImportance());
web_contents()->SetPrimaryMainFrameImportance(ChildProcessImportance::NORMAL);
EXPECT_EQ(ChildProcessImportance::NORMAL,
root->current_frame_host()->GetProcess()->GetEffectiveImportance());
EXPECT_EQ(
ChildProcessImportance::NORMAL,
child->current_frame_host()->GetProcess()->GetEffectiveImportance());
web_contents()->SetPrimaryMainFrameImportance(
ChildProcessImportance::IMPORTANT);
EXPECT_EQ(ChildProcessImportance::IMPORTANT,
root->current_frame_host()->GetProcess()->GetEffectiveImportance());
EXPECT_EQ(
ChildProcessImportance::NORMAL,
child->current_frame_host()->GetProcess()->GetEffectiveImportance());
int old_child_process_id = child->current_frame_host()->GetProcess()->GetID();
GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), url));
int new_child_process_id = child->current_frame_host()->GetProcess()->GetID();
EXPECT_NE(old_child_process_id, new_child_process_id);
EXPECT_EQ(
ChildProcessImportance::NORMAL,
child->current_frame_host()->GetProcess()->GetEffectiveImportance());
EXPECT_EQ(ChildProcessImportance::IMPORTANT,
root->current_frame_host()->GetProcess()->GetEffectiveImportance());
int old_root_process_id = root->current_frame_host()->GetProcess()->GetID();
child = nullptr;
EXPECT_TRUE(NavigateToURLFromRenderer(root, url));
EXPECT_EQ(0u, root->child_count());
int new_root_process_id = root->current_frame_host()->GetProcess()->GetID();
EXPECT_NE(old_root_process_id, new_root_process_id);
EXPECT_EQ(ChildProcessImportance::IMPORTANT,
root->current_frame_host()->GetProcess()->GetEffectiveImportance());
}
class TouchSelectionControllerClientTestWrapper
: public ui::TouchSelectionControllerClient {
public:
explicit TouchSelectionControllerClientTestWrapper(
ui::TouchSelectionControllerClient* client)
: expected_event_(ui::SELECTION_HANDLES_SHOWN), client_(client) {}
TouchSelectionControllerClientTestWrapper(
const TouchSelectionControllerClientTestWrapper&) = delete;
TouchSelectionControllerClientTestWrapper& operator=(
const TouchSelectionControllerClientTestWrapper&) = delete;
~TouchSelectionControllerClientTestWrapper() override {}
void InitWaitForSelectionEvent(ui::SelectionEventType expected_event) {
DCHECK(!run_loop_);
expected_event_ = expected_event;
run_loop_ = std::make_unique<base::RunLoop>();
}
void Wait() {
DCHECK(run_loop_);
run_loop_->Run();
run_loop_.reset();
}
private:
void OnSelectionEvent(ui::SelectionEventType event) override {
client_->OnSelectionEvent(event);
if (run_loop_ && event == expected_event_)
run_loop_->Quit();
}
bool SupportsAnimation() const override {
return client_->SupportsAnimation();
}
void SetNeedsAnimate() override { client_->SetNeedsAnimate(); }
void MoveCaret(const gfx::PointF& position) override {
client_->MoveCaret(position);
}
void MoveRangeSelectionExtent(const gfx::PointF& extent) override {
client_->MoveRangeSelectionExtent(extent);
}
void SelectBetweenCoordinates(const gfx::PointF& base,
const gfx::PointF& extent) override {
client_->SelectBetweenCoordinates(base, extent);
}
std::unique_ptr<ui::TouchHandleDrawable> CreateDrawable() override {
return client_->CreateDrawable();
}
void DidScroll() override {}
void OnDragUpdate(const ui::TouchSelectionDraggable::Type type,
const gfx::PointF& position) override {}
ui::SelectionEventType expected_event_;
std::unique_ptr<base::RunLoop> run_loop_;
raw_ptr<ui::TouchSelectionControllerClient> client_;
};
class TouchSelectionControllerClientAndroidSiteIsolationTest
: public SitePerProcessBrowserTest {
public:
TouchSelectionControllerClientAndroidSiteIsolationTest()
: root_rwhv_(nullptr),
child_rwhv_(nullptr),
child_frame_tree_node_(nullptr),
selection_controller_client_(nullptr) {}
void SetUpCommandLine(base::CommandLine* command_line) override {
SitePerProcessBrowserTestBase::SetUpCommandLine(command_line);
IsolateAllSitesForTesting(command_line);
}
RenderWidgetHostViewAndroid* GetRenderWidgetHostViewAndroid() {
return static_cast<RenderWidgetHostViewAndroid*>(
shell()->web_contents()->GetRenderWidgetHostView());
}
void SelectWithLongPress(gfx::Point point) {
RenderWidgetHostViewAndroid* main_view = GetRenderWidgetHostViewAndroid();
SendTouch(main_view, ui::MotionEvent::Action::DOWN, point);
DelayBy(base::Milliseconds(2000));
SendTouch(main_view, ui::MotionEvent::Action::UP, point);
}
void SimpleTap(gfx::Point point) {
RenderWidgetHostViewAndroid* main_view = GetRenderWidgetHostViewAndroid();
SendTouch(main_view, ui::MotionEvent::Action::DOWN, point);
DelayBy(base::Milliseconds(300));
SendTouch(main_view, ui::MotionEvent::Action::UP, point);
}
void SetupTest() {
GURL test_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
EXPECT_TRUE(NavigateToURL(shell(), test_url));
frame_observer_ = std::make_unique<RenderFrameSubmissionObserver>(
shell()->web_contents());
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
EXPECT_EQ(
" Site A\n"
" +--Site A\n"
"Where A = http://a.com/",
FrameTreeVisualizer().DepictFrameTree(root));
TestNavigationObserver observer(shell()->web_contents());
EXPECT_EQ(1u, root->child_count());
child_frame_tree_node_ = root->child_at(0);
root_rwhv_ = static_cast<RenderWidgetHostViewAndroid*>(
root->current_frame_host()->GetRenderWidgetHost()->GetView());
selection_controller_client_ =
new TouchSelectionControllerClientTestWrapper(
root_rwhv_->GetSelectionControllerClientManagerForTesting());
root_rwhv_->SetSelectionControllerClientForTesting(
base::WrapUnique(selection_controller_client_.get()));
GURL child_url(
embedded_test_server()->GetURL("b.com", "/touch_selection.html"));
EXPECT_TRUE(
NavigateToURLFromRenderer(child_frame_tree_node_.get(), child_url));
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" +--Site B ------- proxies for A\n"
"Where A = http://a.com/\n"
" B = http://b.com/",
FrameTreeVisualizer().DepictFrameTree(root));
child_frame_tree_node_ = root->child_at(0);
WaitForHitTestData(child_frame_tree_node_->current_frame_host());
child_rwhv_ = static_cast<RenderWidgetHostViewChildFrame*>(
child_frame_tree_node_->current_frame_host()
->GetRenderWidgetHost()
->GetView());
EXPECT_EQ(child_url, observer.last_navigation_url());
EXPECT_TRUE(observer.last_navigation_succeeded());
}
void ShutdownTest() {
ASSERT_TRUE(frame_observer_);
frame_observer_.reset();
}
gfx::PointF GetPointInChild() {
gfx::PointF point_f;
std::string str = EvalJs(child_frame_tree_node_->current_frame_host(),
"get_point_inside_text()")
.ExtractString();
ConvertJSONToPoint(str, &point_f);
point_f = child_rwhv()->TransformPointToRootCoordSpaceF(point_f);
return point_f;
}
void VerifyHandlePosition() {
ui::TouchSelectionController* touch_selection_controller =
root_rwhv()->touch_selection_controller();
bool handles_in_place = false;
while (!handles_in_place) {
gfx::PointF selection_start =
touch_selection_controller->GetStartPosition();
gfx::PointF selection_end = touch_selection_controller->GetEndPosition();
gfx::RectF handle_start =
touch_selection_controller->GetStartHandleRect();
gfx::RectF handle_end = touch_selection_controller->GetEndHandleRect();
if (handle_start.IsEmpty()) {
handles_in_place = true;
} else {
bool has_end_handle =
!touch_selection_controller->GetEndHandleRect().IsEmpty();
bool start_near_y =
std::abs(selection_start.y() - handle_start.y()) <= 3.f;
bool start_in_x_range = selection_start.x() >= handle_start.x() &&
selection_start.x() <= handle_start.right();
bool end_near_y = std::abs(selection_end.y() - handle_end.y()) <= 3.f;
bool end_in_x_range = selection_end.x() >= handle_end.x() &&
selection_end.x() <= handle_end.right();
handles_in_place = start_near_y && start_in_x_range && end_near_y &&
end_in_x_range && has_end_handle;
}
if (!handles_in_place)
DelayBy(base::Milliseconds(100));
}
}
RenderWidgetHostViewAndroid* root_rwhv() { return root_rwhv_; }
RenderWidgetHostViewChildFrame* child_rwhv() { return child_rwhv_; }
float PageScaleFactor() {
return frame_observer_->LastRenderFrameMetadata().page_scale_factor;
}
TouchSelectionControllerClientTestWrapper* selection_controller_client() {
return selection_controller_client_;
}
void OnSyntheticGestureSent() {
gesture_run_loop_ = std::make_unique<base::RunLoop>();
gesture_run_loop_->Run();
}
void OnSyntheticGestureCompleted(SyntheticGesture::Result result) {
EXPECT_EQ(SyntheticGesture::GESTURE_FINISHED, result);
gesture_run_loop_->Quit();
}
protected:
void DelayBy(base::TimeDelta delta) {
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE, run_loop.QuitClosure(), delta);
run_loop.Run();
}
private:
void SendTouch(RenderWidgetHostViewAndroid* view,
ui::MotionEvent::Action action,
gfx::Point point) {
DCHECK(action >= ui::MotionEvent::Action::DOWN &&
action < ui::MotionEvent::Action::CANCEL);
ui::MotionEventAndroid::Pointer p(0, point.x(), point.y(), 10, 0, 0, 0, 0);
JNIEnv* env = base::android::AttachCurrentThread();
auto time_ns = (ui::EventTimeForNow() - base::TimeTicks()).InNanoseconds();
ui::MotionEventAndroid touch(
env, nullptr, 1.f, 0, 0, 0, base::TimeTicks::FromJavaNanoTime(time_ns),
ui::MotionEventAndroid::GetAndroidAction(action), 1, 0, 0, 0, 0, 0, 0,
0, 0, false, &p, nullptr);
view->OnTouchEvent(touch);
}
raw_ptr<RenderWidgetHostViewAndroid> root_rwhv_;
raw_ptr<RenderWidgetHostViewChildFrame> child_rwhv_;
raw_ptr<FrameTreeNode> child_frame_tree_node_;
std::unique_ptr<RenderFrameSubmissionObserver> frame_observer_;
raw_ptr<TouchSelectionControllerClientTestWrapper>
selection_controller_client_;
std::unique_ptr<base::RunLoop> gesture_run_loop_;
};
IN_PROC_BROWSER_TEST_P(TouchSelectionControllerClientAndroidSiteIsolationTest,
BasicSelectionIsolatedIframe) {
SetupTest();
EXPECT_EQ(ui::TouchSelectionController::INACTIVE,
root_rwhv()->touch_selection_controller()->active_status());
gfx::PointF point_f = GetPointInChild();
selection_controller_client()->InitWaitForSelectionEvent(
ui::SELECTION_HANDLES_SHOWN);
SelectWithLongPress(gfx::Point(point_f.x(), point_f.y()));
selection_controller_client()->Wait();
EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE,
root_rwhv()->touch_selection_controller()->active_status());
VerifyHandlePosition();
selection_controller_client()->InitWaitForSelectionEvent(
ui::SELECTION_HANDLES_CLEARED);
gfx::PointF point_inside_iframe =
child_rwhv()->TransformPointToRootCoordSpaceF(gfx::PointF(+5.f, +5.f));
SimpleTap(gfx::Point(point_inside_iframe.x(), point_inside_iframe.y()));
selection_controller_client()->Wait();
EXPECT_EQ(ui::TouchSelectionController::INACTIVE,
root_rwhv()->touch_selection_controller()->active_status());
DelayBy(base::Milliseconds(2000));
selection_controller_client()->InitWaitForSelectionEvent(
ui::SELECTION_HANDLES_SHOWN);
SelectWithLongPress(gfx::Point(point_f.x(), point_f.y()));
selection_controller_client()->Wait();
EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE,
root_rwhv()->touch_selection_controller()->active_status());
selection_controller_client()->InitWaitForSelectionEvent(
ui::SELECTION_HANDLES_CLEARED);
gfx::PointF point_outside_iframe =
child_rwhv()->TransformPointToRootCoordSpaceF(gfx::PointF(-5.f, -5.f));
SimpleTap(gfx::Point(point_outside_iframe.x(), point_outside_iframe.y()));
selection_controller_client()->Wait();
EXPECT_EQ(ui::TouchSelectionController::INACTIVE,
root_rwhv()->touch_selection_controller()->active_status());
ShutdownTest();
}
#if BUILDFLAG(IS_ANDROID)
#define MAYBE_SelectionThenPinchInOOPIF DISABLED_SelectionThenPinchInOOPIF
#else
#define MAYBE_SelectionThenPinchInOOPIF SelectionThenPinchInOOPIF
#endif
IN_PROC_BROWSER_TEST_P(TouchSelectionControllerClientAndroidSiteIsolationTest,
MAYBE_SelectionThenPinchInOOPIF) {
SetupTest();
EXPECT_EQ(ui::TouchSelectionController::INACTIVE,
root_rwhv()->touch_selection_controller()->active_status());
gfx::PointF point_f = GetPointInChild();
selection_controller_client()->InitWaitForSelectionEvent(
ui::SELECTION_HANDLES_SHOWN);
SelectWithLongPress(gfx::Point(point_f.x(), point_f.y()));
selection_controller_client()->Wait();
EXPECT_EQ(ui::TouchSelectionController::SELECTION_ACTIVE,
root_rwhv()->touch_selection_controller()->active_status());
VerifyHandlePosition();
float page_scale_delta = 2.f;
float current_page_scale = PageScaleFactor();
float target_page_scale = current_page_scale * page_scale_delta;
SyntheticPinchGestureParams params;
params.anchor = point_f;
params.scale_factor = page_scale_delta;
auto synthetic_pinch_gesture =
std::make_unique<SyntheticTouchscreenPinchGesture>(params);
auto* host =
static_cast<RenderWidgetHostImpl*>(root_rwhv()->GetRenderWidgetHost());
InputEventAckWaiter gesture_pinch_end_waiter(
host, blink::WebInputEvent::Type::kGesturePinchEnd);
host->QueueSyntheticGesture(
std::move(synthetic_pinch_gesture),
base::BindOnce(&TouchSelectionControllerClientAndroidSiteIsolationTest::
OnSyntheticGestureCompleted,
base::Unretained(this)));
OnSyntheticGestureSent();
gesture_pinch_end_waiter.Wait();
VerifyHandlePosition();
const float kScaleFactorTolerance = 0.05f;
EXPECT_NEAR(target_page_scale, PageScaleFactor(), kScaleFactorTolerance);
ShutdownTest();
}
#endif
class TouchEventObserver : public RenderWidgetHost::InputEventObserver {
public:
TouchEventObserver(std::vector<uint32_t>* outgoing_touch_event_ids,
std::vector<uint32_t>* acked_touch_event_ids)
: outgoing_touch_event_ids_(outgoing_touch_event_ids),
acked_touch_event_ids_(acked_touch_event_ids) {}
TouchEventObserver(const TouchEventObserver&) = delete;
TouchEventObserver& operator=(const TouchEventObserver&) = delete;
void OnInputEvent(const blink::WebInputEvent& event) override {
if (!blink::WebInputEvent::IsTouchEventType(event.GetType()))
return;
const auto& touch_event = static_cast<const blink::WebTouchEvent&>(event);
outgoing_touch_event_ids_->push_back(touch_event.unique_touch_event_id);
}
void OnInputEventAck(blink::mojom::InputEventResultSource source,
blink::mojom::InputEventResultState state,
const blink::WebInputEvent& event) override {
if (!blink::WebInputEvent::IsTouchEventType(event.GetType()))
return;
const auto& touch_event = static_cast<const blink::WebTouchEvent&>(event);
acked_touch_event_ids_->push_back(touch_event.unique_touch_event_id);
}
private:
raw_ptr<std::vector<uint32_t>> outgoing_touch_event_ids_;
raw_ptr<std::vector<uint32_t>> acked_touch_event_ids_;
};
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
DISABLED_TouchEventAckQueueOrdering) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
ASSERT_EQ(1u, root->child_count());
FrameTreeNode* child_node = root->child_at(0);
EXPECT_TRUE(ExecJs(child_node,
"touch_event_count = 0;\
function touch_handler(ev) {\
var start = Date.now();\
while (Date.now() < start + 1000) {}\
touch_event_count++;\
}\
document.body.addEventListener('touchstart', touch_handler,\
{ passive : false });\
document.body.addEventListener('touchend', touch_handler,\
{ passive : false });"));
WaitForHitTestData(child_node->current_frame_host());
auto* root_host = static_cast<RenderWidgetHostImpl*>(
root->current_frame_host()->GetRenderWidgetHost());
auto* child_host = static_cast<RenderWidgetHostImpl*>(
child_node->current_frame_host()->GetRenderWidgetHost());
std::vector<uint32_t> outgoing_touch_event_ids;
std::vector<uint32_t> acked_touch_event_ids;
TouchEventObserver parent_touch_event_observer(&outgoing_touch_event_ids,
&acked_touch_event_ids);
TouchEventObserver child_touch_event_observer(&outgoing_touch_event_ids,
&acked_touch_event_ids);
root_host->AddInputEventObserver(&parent_touch_event_observer);
child_host->AddInputEventObserver(&child_touch_event_observer);
InputEventAckWaiter root_ack_waiter(root_host,
blink::WebInputEvent::Type::kTouchEnd);
InputEventAckWaiter child_ack_waiter(child_host,
blink::WebInputEvent::Type::kTouchEnd);
InputEventAckWaiter child_gesture_tap_ack_waiter(
child_host, blink::WebInputEvent::Type::kGestureTap);
gfx::PointF child_tap_point;
{
std::string str = EvalJs(child_node,
"var rect = document.body.getBoundingClientRect();\
var point = {\
x: rect.left + rect.width / 2,\
y: rect.top + rect.height / 2\
};\
JSON.stringify(point);")
.ExtractString();
ConvertJSONToPoint(str, &child_tap_point);
child_tap_point = child_node->current_frame_host()
->GetView()
->TransformPointToRootCoordSpaceF(child_tap_point);
}
SyntheticTapGestureParams child_tap_params;
child_tap_params.position = child_tap_point;
child_tap_params.gesture_source_type =
content::mojom::GestureSourceType::kTouchInput;
child_tap_params.duration_ms = 300.f;
auto child_tap_gesture =
std::make_unique<SyntheticTapGesture>(child_tap_params);
SyntheticTapGestureParams root_tap_params;
root_tap_params.position = gfx::PointF(5.f, 5.f);
root_tap_params.duration_ms = 300.f;
root_tap_params.gesture_source_type =
content::mojom::GestureSourceType::kTouchInput;
auto root_tap_gesture =
std::make_unique<SyntheticTapGesture>(root_tap_params);
root_host->QueueSyntheticGestureCompleteImmediately(
std::move(child_tap_gesture));
root_host->QueueSyntheticGesture(
std::move(root_tap_gesture),
base::BindOnce([](SyntheticGesture::Result result) {
EXPECT_EQ(SyntheticGesture::GESTURE_FINISHED, result);
}));
root_ack_waiter.Wait();
child_ack_waiter.Wait();
EXPECT_EQ(2, EvalJs(child_node, "touch_event_count;"));
EXPECT_EQ(4u, outgoing_touch_event_ids.size());
EXPECT_EQ(4u, acked_touch_event_ids.size());
EXPECT_EQ(outgoing_touch_event_ids[2], acked_touch_event_ids[0]);
EXPECT_EQ(outgoing_touch_event_ids[3], acked_touch_event_ids[1]);
child_gesture_tap_ack_waiter.Wait();
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
ActiveSandboxFlagsMaintainedAcrossNavigation) {
GURL main_url(
embedded_test_server()->GetURL("a.com", "/sandbox_main_frame_csp.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
ASSERT_EQ(1u, root->child_count());
EXPECT_EQ(
" Site A\n"
" +--Site A\n"
"Where A = http://a.com/",
DepictFrameTree(root));
FrameTreeNode* child_node = root->child_at(0);
EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
child_node->current_frame_host()->GetSiteInstance());
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
root->pending_frame_policy().sandbox_flags);
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
root->effective_frame_policy().sandbox_flags);
EXPECT_EQ(
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kAutomaticFeatures &
~network::mojom::WebSandboxFlags::kPointerLock &
~network::mojom::WebSandboxFlags::kPopups &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kTopNavigationToCustomProtocols,
root->active_sandbox_flags());
EXPECT_EQ(
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kAutomaticFeatures &
~network::mojom::WebSandboxFlags::kPopups &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kTopNavigationToCustomProtocols,
root->child_at(0)->pending_frame_policy().sandbox_flags);
EXPECT_EQ(
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kAutomaticFeatures &
~network::mojom::WebSandboxFlags::kPopups &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kTopNavigationToCustomProtocols,
root->child_at(0)->effective_frame_policy().sandbox_flags);
EXPECT_EQ(
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kAutomaticFeatures &
~network::mojom::WebSandboxFlags::kPopups &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kTopNavigationToCustomProtocols,
root->child_at(0)->active_sandbox_flags());
GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), frame_url));
EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
child_node->current_frame_host()->GetSiteInstance());
EXPECT_EQ(
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kAutomaticFeatures &
~network::mojom::WebSandboxFlags::kPopups &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kTopNavigationToCustomProtocols,
root->child_at(0)->active_sandbox_flags());
EXPECT_EQ(
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kAutomaticFeatures &
~network::mojom::WebSandboxFlags::kPopups &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kTopNavigationToCustomProtocols,
root->child_at(0)->pending_frame_policy().sandbox_flags);
EXPECT_EQ(
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kAutomaticFeatures &
~network::mojom::WebSandboxFlags::kPopups &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kTopNavigationToCustomProtocols,
root->child_at(0)->effective_frame_policy().sandbox_flags);
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
ActiveSandboxFlagsRetainedAfterUnload) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/sandboxed_main_frame_script.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
RenderFrameHostImpl* rfh =
static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryMainFrame();
EXPECT_EQ(
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kAutomaticFeatures &
~network::mojom::WebSandboxFlags::kPointerLock &
~network::mojom::WebSandboxFlags::kPopups &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kTopNavigationToCustomProtocols,
rfh->active_sandbox_flags());
EXPECT_TRUE(ExecJs(rfh, "window.onunload=function(e){ while(1); };\n"));
rfh->DisableUnloadTimerForTesting();
RenderFrameDeletedObserver rfh_observer(rfh);
TestFrameNavigationObserver commit_observer(root);
shell()->LoadURL(
GURL(embedded_test_server()->GetURL("b.com", "/title1.html")));
commit_observer.WaitForCommit();
ASSERT_TRUE(rfh->IsRenderFrameLive());
EXPECT_THAT(
rfh->lifecycle_state(),
testing::AnyOf(
testing::Eq(
RenderFrameHostImpl::LifecycleStateImpl::kRunningUnloadHandlers),
testing::Eq(
RenderFrameHostImpl::LifecycleStateImpl::kInBackForwardCache)));
ASSERT_FALSE(rfh_observer.deleted());
EXPECT_EQ(
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kAutomaticFeatures &
~network::mojom::WebSandboxFlags::kPointerLock &
~network::mojom::WebSandboxFlags::kPopups &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kTopNavigationToCustomProtocols,
rfh->active_sandbox_flags());
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
root->effective_frame_policy().sandbox_flags);
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
ActiveSandboxFlagsCorrectInProxies) {
GURL main_url(embedded_test_server()->GetURL(
"foo.com", "/cross_site_iframe_factory.html?foo(bar)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
TestNavigationObserver observer(shell()->web_contents());
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" +--Site B ------- proxies for A\n"
"Where A = http://foo.com/\n"
" B = http://bar.com/",
DepictFrameTree(root));
EXPECT_TRUE(NavigateToURLFromRenderer(
root->child_at(0),
embedded_test_server()->GetURL("bar.com", "/csp_sandboxed_frame.html")));
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" +--Site B ------- proxies for A\n"
" |--Site B -- proxies for A\n"
" +--Site B -- proxies for A\n"
"Where A = http://foo.com/\n"
" B = http://bar.com/",
DepictFrameTree(root));
EXPECT_TRUE(NavigateToURLFromRenderer(
root->child_at(0)->child_at(0),
embedded_test_server()->GetURL("foo.com", "/title1.html")));
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" +--Site B ------- proxies for A\n"
" |--Site A -- proxies for B\n"
" +--Site B -- proxies for A\n"
"Where A = http://foo.com/\n"
" B = http://bar.com/",
DepictFrameTree(root));
EXPECT_EQ(
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kAutomaticFeatures,
root->child_at(0)->child_at(0)->effective_frame_policy().sandbox_flags);
EXPECT_EQ(
root->child_at(0)->child_at(0)->active_sandbox_flags(),
root->child_at(0)->child_at(0)->effective_frame_policy().sandbox_flags);
EXPECT_EQ(true, EvalJs(root->child_at(0)->child_at(0),
"!window.open('data:text/html,dataurl');"));
EXPECT_EQ(1u, Shell::windows().size());
EXPECT_TRUE(NavigateToURLFromRenderer(
root->child_at(0)->child_at(0),
embedded_test_server()->GetURL("baz.com", "/title1.html")));
EXPECT_EQ(
" Site A ------------ proxies for B C\n"
" +--Site B ------- proxies for A C\n"
" |--Site C -- proxies for A B\n"
" +--Site B -- proxies for A C\n"
"Where A = http://foo.com/\n"
" B = http://bar.com/\n"
" C = http://baz.com/",
DepictFrameTree(root));
EXPECT_EQ(
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kAutomaticFeatures,
root->child_at(0)->child_at(0)->effective_frame_policy().sandbox_flags);
EXPECT_EQ(
root->child_at(0)->child_at(0)->active_sandbox_flags(),
root->child_at(0)->child_at(0)->effective_frame_policy().sandbox_flags);
EXPECT_EQ(true, EvalJs(root->child_at(0)->child_at(0),
"!window.open('data:text/html,dataurl');"));
EXPECT_EQ(1u, Shell::windows().size());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
ActiveSandboxFlagsCorrectAfterUpdate) {
GURL main_url(embedded_test_server()->GetURL(
"foo.com", "/cross_site_iframe_factory.html?foo(bar)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
TestNavigationObserver observer(shell()->web_contents());
EXPECT_TRUE(NavigateToURLFromRenderer(
root->child_at(0),
embedded_test_server()->GetURL("bar.com", "/csp_sandboxed_frame.html")));
EXPECT_TRUE(NavigateToURLFromRenderer(
root->child_at(0)->child_at(0),
embedded_test_server()->GetURL("foo.com", "/title1.html")));
EXPECT_EQ(
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kAutomaticFeatures,
root->child_at(0)->child_at(0)->effective_frame_policy().sandbox_flags);
EXPECT_EQ(
root->child_at(0)->child_at(0)->active_sandbox_flags(),
root->child_at(0)->child_at(0)->effective_frame_policy().sandbox_flags);
EXPECT_EQ(true, EvalJs(root->child_at(0)->child_at(0),
"!window.open('data:text/html,dataurl');"));
EXPECT_EQ(1u, Shell::windows().size());
EXPECT_TRUE(ExecJs(root->child_at(0),
"document.querySelector('iframe').sandbox = "
" 'allow-scripts allow-popups';"));
EXPECT_TRUE(NavigateToURLFromRenderer(
root->child_at(0)->child_at(0),
embedded_test_server()->GetURL("foo.com", "/title2.html")));
EXPECT_EQ(
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kAutomaticFeatures,
root->child_at(0)->child_at(0)->effective_frame_policy().sandbox_flags);
EXPECT_EQ(
root->child_at(0)->child_at(0)->active_sandbox_flags(),
root->child_at(0)->child_at(0)->effective_frame_policy().sandbox_flags);
EXPECT_EQ(true, EvalJs(root->child_at(0)->child_at(0),
"!window.open('data:text/html,dataurl');"));
EXPECT_EQ(1u, Shell::windows().size());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
ActiveSandboxFlagsCorrectWhenCleared) {
GURL main_url(
embedded_test_server()->GetURL("foo.com", "/sandboxed_frames_csp.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
TestNavigationObserver observer(shell()->web_contents());
EXPECT_EQ(network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kPointerLock &
~network::mojom::WebSandboxFlags::kOrientationLock &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kAutomaticFeatures,
root->child_at(1)->effective_frame_policy().sandbox_flags);
EXPECT_EQ(network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kPointerLock &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kAutomaticFeatures,
root->child_at(1)->active_sandbox_flags());
EXPECT_TRUE(NavigateToURLFromRenderer(
root->child_at(1), embedded_test_server()->GetURL(
"bar.com", "/sandboxed_child_frame.html")));
EXPECT_EQ(network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kPointerLock &
~network::mojom::WebSandboxFlags::kOrientationLock &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kAutomaticFeatures,
root->child_at(1)->effective_frame_policy().sandbox_flags);
EXPECT_EQ(network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kPointerLock &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kAutomaticFeatures,
root->child_at(1)->active_sandbox_flags());
EXPECT_TRUE(ExecJs(root,
"document.querySelectorAll('iframe')[1]"
".removeAttribute('sandbox');"));
EXPECT_TRUE(NavigateToURLFromRenderer(
root->child_at(1),
embedded_test_server()->GetURL(
"bar.com", "/cross_site_iframe_factory.html?bar(foo)")));
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
root->child_at(1)->effective_frame_policy().sandbox_flags);
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
root->child_at(1)->active_sandbox_flags());
EXPECT_EQ(
network::mojom::WebSandboxFlags::kNone,
root->child_at(1)->child_at(0)->effective_frame_policy().sandbox_flags);
EXPECT_EQ(
root->child_at(1)->child_at(0)->active_sandbox_flags(),
root->child_at(1)->child_at(0)->effective_frame_policy().sandbox_flags);
EXPECT_EQ(true, EvalJs(root->child_at(1)->child_at(0),
"!!window.open('data:text/html,dataurl');"));
EXPECT_EQ(2u, Shell::windows().size());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
SubframeReusesExistingProcess) {
GURL foo_url(
embedded_test_server()->GetURL("foo.com", "/page_with_iframe.html"));
EXPECT_TRUE(NavigateToURL(shell(), foo_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child = root->child_at(0);
GURL bar_url(
embedded_test_server()->GetURL("bar.com", "/page_with_iframe.html"));
Shell* second_shell = CreateBrowser();
EXPECT_TRUE(NavigateToURL(second_shell, bar_url));
scoped_refptr<SiteInstanceImpl> second_shell_instance =
static_cast<SiteInstanceImpl*>(second_shell->web_contents()
->GetPrimaryMainFrame()
->GetSiteInstance());
EXPECT_FALSE(second_shell_instance->IsRelatedSiteInstance(
root->current_frame_host()->GetSiteInstance()));
RenderProcessHost* bar_process = second_shell_instance->GetProcess();
EXPECT_EQ(SiteInstanceImpl::ProcessReusePolicy::DEFAULT,
second_shell_instance->process_reuse_policy());
NavigateIframeToURL(web_contents(), "test_iframe", bar_url);
EXPECT_EQ(bar_url, child->current_url());
EXPECT_EQ(bar_process, child->current_frame_host()->GetProcess());
EXPECT_EQ(
SiteInstanceImpl::ProcessReusePolicy::REUSE_PENDING_OR_COMMITTED_SITE,
child->current_frame_host()->GetSiteInstance()->process_reuse_policy());
EXPECT_TRUE(child->current_frame_host()->IsCrossProcessSubframe());
EXPECT_EQ(
bar_url.host(),
child->current_frame_host()->GetSiteInstance()->GetSiteURL().host());
EXPECT_NE(second_shell_instance,
child->current_frame_host()->GetSiteInstance());
EXPECT_FALSE(second_shell_instance->IsRelatedSiteInstance(
child->current_frame_host()->GetSiteInstance()));
EXPECT_TRUE(NavigateToURL(second_shell, foo_url));
EXPECT_NE(bar_process,
second_shell->web_contents()->GetPrimaryMainFrame()->GetProcess());
NavigateIframeToURL(second_shell->web_contents(), "test_iframe", bar_url);
FrameTreeNode* second_subframe =
static_cast<WebContentsImpl*>(second_shell->web_contents())
->GetPrimaryFrameTree()
.root()
->child_at(0);
EXPECT_EQ(bar_process, second_subframe->current_frame_host()->GetProcess());
EXPECT_NE(child->current_frame_host()->GetSiteInstance(),
second_subframe->current_frame_host()->GetSiteInstance());
Shell* third_shell = CreateBrowser();
EXPECT_TRUE(NavigateToURL(third_shell, bar_url));
SiteInstanceImpl* third_shell_instance = static_cast<SiteInstanceImpl*>(
third_shell->web_contents()->GetPrimaryMainFrame()->GetSiteInstance());
EXPECT_NE(third_shell_instance,
second_subframe->current_frame_host()->GetSiteInstance());
EXPECT_NE(third_shell_instance,
child->current_frame_host()->GetSiteInstance());
EXPECT_NE(third_shell_instance->GetProcess(), bar_process);
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
NoProcessSharingAfterSubframeReusesExistingProcess) {
GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), foo_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
SiteInstanceImpl* foo_instance =
root->current_frame_host()->GetSiteInstance();
GURL bar_url(
embedded_test_server()->GetURL("bar.com", "/page_with_iframe.html"));
Shell* second_shell = CreateBrowser();
EXPECT_TRUE(NavigateToURL(second_shell, bar_url));
FrameTreeNode* second_root =
static_cast<WebContentsImpl*>(second_shell->web_contents())
->GetPrimaryFrameTree()
.root();
FrameTreeNode* second_child = second_root->child_at(0);
scoped_refptr<SiteInstanceImpl> bar_instance =
second_root->current_frame_host()->GetSiteInstance();
EXPECT_FALSE(bar_instance->IsRelatedSiteInstance(foo_instance));
NavigateIframeToURL(second_shell->web_contents(), "test_iframe", foo_url);
EXPECT_EQ(foo_url, second_child->current_url());
scoped_refptr<SiteInstanceImpl> second_child_foo_instance =
second_child->current_frame_host()->GetSiteInstance();
EXPECT_EQ(
SiteInstanceImpl::ProcessReusePolicy::REUSE_PENDING_OR_COMMITTED_SITE,
second_child_foo_instance->process_reuse_policy());
EXPECT_NE(foo_instance, second_child_foo_instance);
EXPECT_EQ(foo_instance->GetProcess(),
second_child_foo_instance->GetProcess());
EXPECT_TRUE(NavigateToURL(second_shell, foo_url));
SiteInstanceImpl* new_instance =
second_root->current_frame_host()->GetSiteInstance();
EXPECT_NE(second_child_foo_instance, new_instance);
EXPECT_FALSE(second_child_foo_instance->IsRelatedSiteInstance(new_instance));
EXPECT_FALSE(bar_instance->IsRelatedSiteInstance(new_instance));
EXPECT_FALSE(foo_instance->IsRelatedSiteInstance(new_instance));
EXPECT_NE(new_instance->GetProcess(), foo_instance->GetProcess());
EXPECT_NE(new_instance->GetProcess(), bar_instance->GetProcess());
}
namespace {
class CommitMessageOrderReverser : public DidCommitNavigationInterceptor {
public:
using DidStartDeferringCommitCallback =
base::OnceCallback<void(RenderFrameHost*)>;
CommitMessageOrderReverser(
WebContents* web_contents,
const GURL& deferred_url,
DidStartDeferringCommitCallback deferred_url_triggered_action)
: DidCommitNavigationInterceptor(web_contents),
deferred_url_(deferred_url),
deferred_url_triggered_action_(
std::move(deferred_url_triggered_action)) {}
CommitMessageOrderReverser(const CommitMessageOrderReverser&) = delete;
CommitMessageOrderReverser& operator=(const CommitMessageOrderReverser&) =
delete;
~CommitMessageOrderReverser() override = default;
void WaitForBothCommits() { outer_run_loop.Run(); }
protected:
bool WillProcessDidCommitNavigation(
RenderFrameHost* render_frame_host,
NavigationRequest* navigation_request,
mojom::DidCommitProvisionalLoadParamsPtr* params,
mojom::DidCommitProvisionalLoadInterfaceParamsPtr* interface_params)
override {
if ((**params).url == deferred_url_) {
std::move(deferred_url_triggered_action_).Run(render_frame_host);
base::RunLoop nested_run_loop(base::RunLoop::Type::kNestableTasksAllowed);
nested_loop_quit_ = nested_run_loop.QuitClosure();
nested_run_loop.Run();
outer_run_loop.Quit();
} else if (nested_loop_quit_) {
std::move(nested_loop_quit_).Run();
}
return true;
}
private:
base::RunLoop outer_run_loop;
base::OnceClosure nested_loop_quit_;
const GURL deferred_url_;
DidStartDeferringCommitCallback deferred_url_triggered_action_;
};
}
#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH)
#define MAYBE_OOPIFDetachDuringAnimation DISABLED_OOPIFDetachDuringAnimation
#else
#define MAYBE_OOPIFDetachDuringAnimation OOPIFDetachDuringAnimation
#endif
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
MAYBE_OOPIFDetachDuringAnimation) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/frame_tree/frame-detached-in-animationstart-event.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" +--Site B ------- proxies for A\n"
" +--Site A -- proxies for B\n"
"Where A = http://a.com/\n"
" B = http://b.com/",
DepictFrameTree(root));
FrameTreeNode* nested_child = root->child_at(0)->child_at(0);
WaitForHitTestData(nested_child->current_frame_host());
EXPECT_TRUE(ExecJs(nested_child->current_frame_host(), "startTest();"));
EXPECT_EQ(true, EvalJs(root->current_frame_host(), "true;"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
IFrameSameDocumentNavigation) {
GURL main_url(embedded_test_server()->GetURL(
"foo.com", "/cross_site_iframe_factory.html?foo(bar)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* iframe = root->child_at(0);
EXPECT_NE(root->current_frame_host()->GetSiteInstance(),
iframe->current_frame_host()->GetSiteInstance());
GURL iframe_fragment_url = GURL(iframe->current_url().spec() + "#foo");
{
TestNavigationObserver observer(shell()->web_contents());
EXPECT_TRUE(ExecJs(iframe->current_frame_host(),
JsReplace("location.href=$1", iframe_fragment_url)));
observer.Wait();
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(iframe_fragment_url, iframe->current_url());
}
{
TestNavigationObserver observer(shell()->web_contents());
EXPECT_TRUE(ExecJs(root->current_frame_host(),
JsReplace("document.getElementById('child-0').src=$1",
iframe_fragment_url)));
observer.Wait();
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(iframe_fragment_url, iframe->current_url());
}
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, SizeAvailableAfterCommit) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child = root->child_at(0);
GURL b_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
TestFrameNavigationObserver commit_observer(child);
NavigationController::LoadURLParams params(b_url);
params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
params.frame_tree_node_id = child->frame_tree_node_id();
child->navigator().controller().LoadURLWithParams(params);
commit_observer.WaitForCommit();
EXPECT_GT(EvalJs(child, "window.innerHeight;").ExtractDouble(), 0);
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
RenderViewHostStaysActiveWithLateUnloadACK) {
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
Shell* popup = OpenPopup(
shell(), embedded_test_server()->GetURL("a.com", "/title2.html"), "foo");
WebContentsImpl* popup_contents =
static_cast<WebContentsImpl*>(popup->web_contents());
RenderFrameHostImpl* rfh = popup_contents->GetPrimaryMainFrame();
RenderViewHostImpl* rvh = rfh->render_view_host();
auto unload_ack_filter = base::BindRepeating([] { return true; });
rfh->SetUnloadACKCallbackForTesting(unload_ack_filter);
rfh->DisableUnloadTimerForTesting();
EXPECT_TRUE(NavigateToURLInSameBrowsingInstance(
popup, embedded_test_server()->GetURL("b.com", "/title3.html")));
EXPECT_FALSE(rvh->is_active());
ASSERT_TRUE(rfh->IsRenderFrameLive());
ASSERT_TRUE(rfh->IsPendingDeletion());
RenderProcessHost* b_process =
popup_contents->GetPrimaryMainFrame()->GetProcess();
RenderProcessHostWatcher crash_observer(
b_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
b_process->Shutdown(0);
crash_observer.Wait();
TestNavigationObserver back_observer(popup_contents);
popup_contents->GetController().GoBack();
rfh->OnUnloaded();
back_observer.Wait();
EXPECT_EQ(popup_contents->GetPrimaryMainFrame()->render_view_host(), rvh);
EXPECT_TRUE(rvh->is_active());
EXPECT_EQ(rvh->GetMainRenderFrameHost(),
popup_contents->GetPrimaryMainFrame());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
SubframeVisibleAfterRenderViewBecomesSwappedOut) {
GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
GURL popup_url(embedded_test_server()->GetURL(
"b.com", "/cross_site_iframe_factory.html?b(b)"));
Shell* popup_shell = OpenPopup(shell()->web_contents(), popup_url, "popup");
FrameTreeNode* popup_child =
static_cast<WebContentsImpl*>(popup_shell->web_contents())
->GetPrimaryFrameTree()
.root()
->child_at(0);
EXPECT_TRUE(NavigateToURLFromRenderer(
popup_child, embedded_test_server()->GetURL("a.com", "/counter.html")));
RenderWidgetHostViewChildFrame* child_view =
static_cast<RenderWidgetHostViewChildFrame*>(
popup_child->current_frame_host()->GetView());
RenderFrameSubmissionObserver frame_counter(
child_view->host_->render_frame_metadata_provider());
while (frame_counter.render_frame_count() < 10)
frame_counter.WaitForAnyFrameSubmission();
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, FrameDepthSimple) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b(c(d(e))))"));
const size_t number_of_nodes = 5;
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* node = web_contents()->GetPrimaryFrameTree().root();
for (unsigned int expected_depth = 0; expected_depth < number_of_nodes;
++expected_depth) {
CheckFrameDepth(expected_depth, node);
if (expected_depth + 1 < number_of_nodes)
node = node->child_at(0);
}
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, FrameDepthTest) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a,b(a))"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
CheckFrameDepth(0u, root);
FrameTreeNode* child0 = root->child_at(0);
{
EXPECT_EQ(1u, child0->current_frame_host()->GetFrameDepth());
RenderProcessHostPriorityClient::Priority priority =
child0->current_frame_host()->GetRenderWidgetHost()->GetPriority();
EXPECT_EQ(0u, priority.frame_depth);
EXPECT_EQ(0u, child0->current_frame_host()->GetProcess()->GetFrameDepth());
}
FrameTreeNode* child1 = root->child_at(1);
CheckFrameDepth(1u, child1);
RenderViewHostImpl* child1_rvh =
child1->current_frame_host()->render_view_host();
EXPECT_FALSE(child1_rvh->is_active());
EXPECT_EQ(RenderProcessHostImpl::kMaxFrameDepthForPriority,
child1_rvh->GetWidget()->GetPriority().frame_depth);
EXPECT_FALSE(static_cast<RenderWidgetHostOwnerDelegate*>(child1_rvh)
->ShouldContributePriorityToProcess());
FrameTreeNode* grand_child = root->child_at(1)->child_at(0);
{
EXPECT_EQ(2u, grand_child->current_frame_host()->GetFrameDepth());
RenderProcessHostPriorityClient::Priority priority =
grand_child->current_frame_host()->GetRenderWidgetHost()->GetPriority();
EXPECT_EQ(2u, priority.frame_depth);
EXPECT_EQ(0u,
grand_child->current_frame_host()->GetProcess()->GetFrameDepth());
}
}
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
#define MAYBE_VisibilityFrameDepthTest DISABLED_VisibilityFrameDepthTest
#else
#define MAYBE_VisibilityFrameDepthTest VisibilityFrameDepthTest
#endif
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
MAYBE_VisibilityFrameDepthTest) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
GURL popup_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
Shell* new_shell = OpenPopup(root->child_at(0), popup_url, "");
FrameTreeNode* popup_root =
static_cast<WebContentsImpl*>(new_shell->web_contents())
->GetPrimaryFrameTree()
.root();
RenderProcessHost* subframe_process =
root->child_at(0)->current_frame_host()->GetProcess();
RenderProcessHost* popup_process =
popup_root->current_frame_host()->GetProcess();
EXPECT_EQ(subframe_process, popup_process);
EXPECT_EQ(2, popup_process->VisibleClientCount());
EXPECT_EQ(0u, popup_process->GetFrameDepth());
new_shell->web_contents()->WasHidden();
EXPECT_EQ(1, popup_process->VisibleClientCount());
EXPECT_EQ(1u, popup_process->GetFrameDepth());
EXPECT_TRUE(NavigateToURLInSameBrowsingInstance(shell(), popup_url));
new_shell->web_contents()->WasHidden();
RenderProcessHost* new_root_process =
root->current_frame_host()->GetProcess();
EXPECT_EQ(new_root_process, popup_process);
EXPECT_EQ(1, popup_process->VisibleClientCount());
EXPECT_EQ(0u, popup_process->GetFrameDepth());
TestNavigationObserver back_load_observer(shell()->web_contents());
shell()->web_contents()->GetController().GoBack();
back_load_observer.Wait();
new_shell->web_contents()->WasHidden();
EXPECT_EQ(1, popup_process->VisibleClientCount());
EXPECT_EQ(1u, popup_process->GetFrameDepth());
new_shell->web_contents()->WasShown();
EXPECT_EQ(2, popup_process->VisibleClientCount());
EXPECT_EQ(0u, popup_process->GetFrameDepth());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
CrossProcessPostMessageWaitsForCurrentScriptToFinish) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_EQ(root, root->frame_tree().GetFocusedFrame());
EXPECT_TRUE(
ExecJs(root->child_at(0), WaitForMessageScript("document.hasFocus()")));
EXPECT_EQ(true, ExecJs(root,
"frames[0].postMessage('','*');\n"
"frames[0].focus();\n"));
EXPECT_EQ(true, EvalJs(root->child_at(0), "onMessagePromise"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
CrossProcessPostMessageAndDetachTarget) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_TRUE(ExecJs(root,
"frames[0].postMessage('','*');\n"
"document.body.removeChild(\n"
" document.querySelector('iframe'));\n"));
EXPECT_EQ(
true,
EvalJs(
root,
"new Promise(resolve => setTimeout(() => { resolve(true); }, 0))"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
LastCommittedURLRetainedAfterUnload) {
GURL start_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
RenderFrameHostImpl* rfh = web_contents()->GetPrimaryMainFrame();
EXPECT_EQ(start_url, rfh->GetLastCommittedURL());
auto unload_ack_filter = base::BindRepeating([] { return true; });
rfh->SetUnloadACKCallbackForTesting(unload_ack_filter);
rfh->DisableUnloadTimerForTesting();
OpenPopup(shell(), embedded_test_server()->GetURL("a.com", "/title2.html"),
"foo");
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL("b.com", "/title3.html")));
EXPECT_TRUE(rfh->IsPendingDeletion());
EXPECT_FALSE(rfh->IsActive());
EXPECT_NE(rfh, web_contents()->GetPrimaryMainFrame());
EXPECT_EQ(start_url, rfh->GetLastCommittedURL());
}
#if BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
GestureManagerListensToChildFrames) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child = root->child_at(0);
GURL b_url(embedded_test_server()->GetURL("b.com", "/scrollable_page.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(child, b_url));
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" +--Site B ------- proxies for A\n"
"Where A = http://a.com/\n"
" B = http://b.com/",
DepictFrameTree(root));
RenderWidgetHost* rwh = root->current_frame_host()->GetRenderWidgetHost();
RenderWidgetHost* child_rwh =
child->current_frame_host()->GetRenderWidgetHost();
RunUntilInputProcessed(rwh);
RunUntilInputProcessed(child_rwh);
RenderWidgetHostViewAndroid* rwhv_root =
static_cast<RenderWidgetHostViewAndroid*>(
root->current_frame_host()->GetRenderWidgetHost()->GetView());
ASSERT_FALSE(
rwhv_root->gesture_listener_manager_->IsScrollInProgressForTesting());
{
blink::WebGestureEvent gesture_scroll_begin(
blink::WebGestureEvent::Type::kGestureScrollBegin,
blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests(),
blink::WebGestureDevice::kTouchscreen);
gesture_scroll_begin.data.scroll_begin.delta_hint_units =
ui::ScrollGranularity::kScrollByPrecisePixel;
gesture_scroll_begin.data.scroll_begin.delta_x_hint = 0.f;
gesture_scroll_begin.data.scroll_begin.delta_y_hint = -5.f;
blink::WebMouseEvent mouse_move(
blink::WebInputEvent::Type::kMouseMove,
blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests());
InputEventAckWaiter mouse_move_waiter(
child_rwh, blink::WebInputEvent::Type::kMouseMove);
child_rwh->ForwardGestureEvent(gesture_scroll_begin);
child_rwh->ForwardMouseEvent(mouse_move);
mouse_move_waiter.Wait();
EXPECT_TRUE(
rwhv_root->gesture_listener_manager_->IsScrollInProgressForTesting());
}
{
blink::WebGestureEvent gesture_scroll_end(
blink::WebGestureEvent::Type::kGestureScrollEnd,
blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests(),
blink::WebGestureDevice::kTouchscreen);
blink::WebMouseEvent mouse_move(
blink::WebInputEvent::Type::kMouseMove,
blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests());
InputEventAckWaiter mouse_move_waiter(
child_rwh, blink::WebInputEvent::Type::kMouseMove);
child_rwh->ForwardGestureEvent(gesture_scroll_end);
child_rwh->ForwardMouseEvent(mouse_move);
mouse_move_waiter.Wait();
EXPECT_FALSE(
rwhv_root->gesture_listener_manager_->IsScrollInProgressForTesting());
}
}
#endif
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, DisplayLockThrottlesOOPIF) {
GURL url_a(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), url_a));
FrameTreeNode* a_frame = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* b_frame = a_frame->child_at(0);
ASSERT_TRUE(EvalJsAfterLifecycleUpdate(a_frame->current_frame_host(), "", "")
.error.empty());
ASSERT_TRUE(EvalJsAfterLifecycleUpdate(b_frame->current_frame_host(), "", "")
.error.empty());
ASSERT_TRUE(EvalJsAfterLifecycleUpdate(
a_frame->current_frame_host(),
"document.body.style = 'content-visibility: hidden'", "")
.error.empty());
static const char kObserverScript[] = R"(
new Promise((resolve, reject) => {
new IntersectionObserver((entries, observer) => {
observer.unobserve(entries[0].target);
resolve(String(entries[0].isIntersecting))
}).observe(document.getElementById('siteNameHeading'))
})
)";
EvalJsResult result1 = EvalJs(b_frame->current_frame_host(), kObserverScript);
ASSERT_TRUE(result1.error.empty());
EXPECT_EQ(result1.ExtractString(), "false");
ASSERT_TRUE(EvalJsAfterLifecycleUpdate(a_frame->current_frame_host(),
"document.body.style = ''", "")
.error.empty());
EvalJsResult result2 = EvalJs(b_frame->current_frame_host(), kObserverScript);
ASSERT_EQ(result2.error, "");
EXPECT_EQ(result2.ExtractString(), "true");
}
namespace {
class ClosePageBeforeCommitHelper : public DidCommitNavigationInterceptor {
public:
explicit ClosePageBeforeCommitHelper(WebContents* web_contents)
: DidCommitNavigationInterceptor(web_contents) {}
ClosePageBeforeCommitHelper(const ClosePageBeforeCommitHelper&) = delete;
ClosePageBeforeCommitHelper& operator=(const ClosePageBeforeCommitHelper&) =
delete;
void Wait() {
run_loop_ = std::make_unique<base::RunLoop>();
run_loop_->Run();
run_loop_.reset();
}
private:
bool WillProcessDidCommitNavigation(
RenderFrameHost* render_frame_host,
NavigationRequest* navigation_request,
mojom::DidCommitProvisionalLoadParamsPtr* params,
mojom::DidCommitProvisionalLoadInterfaceParamsPtr* interface_params)
override {
RenderFrameHostImpl* rfh =
static_cast<RenderFrameHostImpl*>(render_frame_host);
EXPECT_TRUE(rfh->render_view_host()->is_active());
rfh->GetMainFrame()->ClosePage(
RenderFrameHostImpl::ClosePageSource::kBrowser);
if (run_loop_)
run_loop_->Quit();
return true;
}
std::unique_ptr<base::RunLoop> run_loop_;
};
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
CloseTabBeforeSubframeCommits) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
GURL same_site_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
Shell* new_shell = OpenPopup(root, same_site_url, "");
RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1);
EXPECT_TRUE(
ExecJs(root->child_at(0),
"document.body.appendChild(document.createElement('iframe'));"));
frame_observer.Wait();
FrameTreeNode* grandchild = root->child_at(0)->child_at(0);
ClosePageBeforeCommitHelper close_page_helper(web_contents());
EXPECT_TRUE(ExecJs(grandchild, JsReplace("location = $1", same_site_url)));
close_page_helper.Wait();
EXPECT_EQ(true, EvalJs(new_shell, "true;"));
}
class SitePerProcessBrowserTouchActionTest : public SitePerProcessBrowserTest {
public:
SitePerProcessBrowserTouchActionTest() = default;
bool GetTouchActionForceEnableZoom(RenderWidgetHost* rwh) {
InputRouterImpl* input_router = static_cast<InputRouterImpl*>(
static_cast<RenderWidgetHostImpl*>(rwh)->input_router());
return input_router->touch_action_filter_.force_enable_zoom_;
}
void GetTouchActionsForChild(
RenderWidgetHostInputEventRouter* router,
RenderWidgetHostViewBase* rwhv_root,
RenderWidgetHostViewBase* rwhv_child,
const gfx::Point& event_position,
absl::optional<cc::TouchAction>& effective_touch_action,
absl::optional<cc::TouchAction>& allowed_touch_action) {
InputEventAckWaiter ack_observer(
rwhv_child->GetRenderWidgetHost(),
base::BindRepeating([](blink::mojom::InputEventResultSource source,
blink::mojom::InputEventResultState state,
const blink::WebInputEvent& event) {
return event.GetType() == blink::WebGestureEvent::Type::kTouchStart ||
event.GetType() == blink::WebGestureEvent::Type::kTouchMove ||
event.GetType() == blink::WebGestureEvent::Type::kTouchEnd;
}));
InputRouterImpl* input_router = static_cast<InputRouterImpl*>(
static_cast<RenderWidgetHostImpl*>(rwhv_child->GetRenderWidgetHost())
->input_router());
input_router->touch_action_filter_.allowed_touch_action_.reset();
ack_observer.Reset();
blink::SyntheticWebTouchEvent touch_event;
int index = touch_event.PressPoint(event_position.x(), event_position.y());
router->RouteTouchEvent(rwhv_root, &touch_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
ack_observer.Wait();
effective_touch_action.reset();
allowed_touch_action.reset();
effective_touch_action =
input_router->touch_action_filter_.allowed_touch_action_;
allowed_touch_action =
input_router->touch_action_filter_.compositor_allowed_touch_action_;
ack_observer.Reset();
touch_event.MovePoint(index, 1, 1);
router->RouteTouchEvent(rwhv_root, &touch_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
ack_observer.Wait();
ack_observer.Reset();
touch_event.ReleasePoint(index);
router->RouteTouchEvent(rwhv_root, &touch_event,
ui::LatencyInfo(ui::SourceEventType::TOUCH));
ack_observer.Wait();
}
void GiveItSomeTime(const base::TimeDelta& t) {
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE, run_loop.QuitClosure(), t);
run_loop.Run();
}
void WaitForTouchActionUpdated(
MainThreadFrameObserver* root_thread_observer,
MainThreadFrameObserver* child_thread_observer) {
root_thread_observer->Wait();
child_thread_observer->Wait();
root_thread_observer->Wait();
}
};
#if BUILDFLAG(IS_ANDROID)
class EnableForceZoomContentClient
: public ContentBrowserTestContentBrowserClient {
public:
EnableForceZoomContentClient() = default;
EnableForceZoomContentClient(const EnableForceZoomContentClient&) = delete;
EnableForceZoomContentClient& operator=(const EnableForceZoomContentClient&) =
delete;
void OverrideWebkitPrefs(WebContents* web_contents,
blink::web_pref::WebPreferences* prefs) override {
prefs->force_enable_zoom = true;
}
};
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTouchActionTest,
ForceEnableZoomPropagatesToChild) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
ASSERT_EQ(1U, root->child_count());
GURL b_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
FrameTreeNode* child = root->child_at(0);
EXPECT_TRUE(NavigateToURLFromRenderer(child, b_url));
WaitForHitTestData(child->current_frame_host());
RenderWidgetHost* child_rwh =
child->current_frame_host()->GetRenderWidgetHost();
EXPECT_FALSE(GetTouchActionForceEnableZoom(child_rwh));
EnableForceZoomContentClient new_client;
web_contents()->OnWebPreferencesChanged();
EXPECT_TRUE(GetTouchActionForceEnableZoom(child_rwh));
GURL c_url = embedded_test_server()->GetURL("c.com", "/title1.html");
std::string create_frame_script = base::StringPrintf(
"var new_iframe = document.createElement('iframe');"
"new_iframe.src = '%s';"
"document.body.appendChild(new_iframe);",
c_url.spec().c_str());
EXPECT_TRUE(ExecJs(root, create_frame_script));
EXPECT_TRUE(WaitForLoadStop(web_contents()));
ASSERT_EQ(2U, root->child_count());
FrameTreeNode* new_child = root->child_at(1);
EXPECT_NE(root->current_frame_host()->GetRenderWidgetHost(),
new_child->current_frame_host()->GetRenderWidgetHost());
EXPECT_TRUE(GetTouchActionForceEnableZoom(
new_child->current_frame_host()->GetRenderWidgetHost()));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTouchActionTest,
CheckForceEnableZoomValue) {
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL("foo.com", "/title1.html")));
EXPECT_FALSE(GetTouchActionForceEnableZoom(
web_contents()->GetPrimaryMainFrame()->GetRenderViewHost()->GetWidget()));
EnableForceZoomContentClient new_client;
web_contents()->OnWebPreferencesChanged();
EXPECT_TRUE(GetTouchActionForceEnableZoom(
web_contents()->GetPrimaryMainFrame()->GetRenderViewHost()->GetWidget()));
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL("bar.com", "/title2.html")));
EXPECT_TRUE(GetTouchActionForceEnableZoom(
web_contents()->GetPrimaryMainFrame()->GetRenderViewHost()->GetWidget()));
}
#endif
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTouchActionTest,
DISABLED_EffectiveTouchActionPropagatesAcrossFrames) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child = root->child_at(0);
RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
root->current_frame_host()->GetRenderWidgetHost()->GetView());
RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
child->current_frame_host()->GetRenderWidgetHost()->GetView());
std::unique_ptr<MainThreadFrameObserver> root_thread_observer(
new MainThreadFrameObserver(
root->current_frame_host()->GetRenderWidgetHost()));
root_thread_observer->Wait();
GURL b_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(child, b_url));
EXPECT_TRUE(ExecJs(shell(), "document.body.style.touchAction = 'none'"));
WaitForHitTestData(child->current_frame_host());
std::unique_ptr<MainThreadFrameObserver> child_thread_observer(
new MainThreadFrameObserver(
child->current_frame_host()->GetRenderWidgetHost()));
RenderWidgetHostViewChildFrame* child_view =
static_cast<RenderWidgetHostViewChildFrame*>(
child->current_frame_host()->GetRenderWidgetHost()->GetView());
gfx::Point point_inside_child = ToFlooredPoint(
child_view->TransformPointToRootCoordSpaceF(gfx::PointF(+5.f, +5.f)));
RenderWidgetHostInputEventRouter* router =
static_cast<WebContentsImpl*>(web_contents())->GetInputEventRouter();
WaitForTouchActionUpdated(root_thread_observer.get(),
child_thread_observer.get());
absl::optional<cc::TouchAction> effective_touch_action;
absl::optional<cc::TouchAction> allowed_touch_action;
cc::TouchAction expected_touch_action = cc::TouchAction::kPan;
GetTouchActionsForChild(router, rwhv_root, rwhv_child, point_inside_child,
effective_touch_action, allowed_touch_action);
if (allowed_touch_action.has_value())
EXPECT_EQ(expected_touch_action, allowed_touch_action.value());
EXPECT_TRUE(ExecJs(shell(), "document.body.style.touchAction = 'auto'"));
WaitForTouchActionUpdated(root_thread_observer.get(),
child_thread_observer.get());
expected_touch_action = cc::TouchAction::kAuto;
GetTouchActionsForChild(router, rwhv_root, rwhv_child, point_inside_child,
effective_touch_action, allowed_touch_action);
EXPECT_EQ(expected_touch_action, effective_touch_action.has_value()
? effective_touch_action.value()
: cc::TouchAction::kAuto);
if (allowed_touch_action.has_value())
EXPECT_EQ(expected_touch_action, allowed_touch_action.value());
}
IN_PROC_BROWSER_TEST_F(
SitePerProcessBrowserTouchActionTest,
DISABLED_EffectiveTouchActionPropagatesAcrossNestedFrames) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b(c))"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* parent = root->child_at(0);
GURL b_url(embedded_test_server()->GetURL(
"b.com", "/frame_tree/page_with_iframe_in_div.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(parent, b_url));
ASSERT_EQ(1U, parent->child_count());
EXPECT_EQ(
" Site A ------------ proxies for B C\n"
" +--Site B ------- proxies for A C\n"
" +--Site C -- proxies for A B\n"
"Where A = http://a.com/\n"
" B = http://b.com/\n"
" C = http://bar.com/",
DepictFrameTree(root));
FrameTreeNode* child = root->child_at(0)->child_at(0);
RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
root->current_frame_host()->GetRenderWidgetHost()->GetView());
RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
child->current_frame_host()->GetRenderWidgetHost()->GetView());
std::unique_ptr<MainThreadFrameObserver> root_thread_observer(
new MainThreadFrameObserver(
root->current_frame_host()->GetRenderWidgetHost()));
root_thread_observer->Wait();
EXPECT_TRUE(ExecJs(shell(), "document.body.style.touchAction = 'none'"));
WaitForHitTestData(child->current_frame_host());
std::unique_ptr<MainThreadFrameObserver> child_thread_observer(
new MainThreadFrameObserver(
child->current_frame_host()->GetRenderWidgetHost()));
RenderWidgetHostViewChildFrame* child_view =
static_cast<RenderWidgetHostViewChildFrame*>(
child->current_frame_host()->GetRenderWidgetHost()->GetView());
gfx::Point point_inside_child = ToFlooredPoint(
child_view->TransformPointToRootCoordSpaceF(gfx::PointF(+5.f, +5.f)));
RenderWidgetHostInputEventRouter* router =
static_cast<WebContentsImpl*>(web_contents())->GetInputEventRouter();
WaitForTouchActionUpdated(root_thread_observer.get(),
child_thread_observer.get());
absl::optional<cc::TouchAction> effective_touch_action;
absl::optional<cc::TouchAction> allowed_touch_action;
cc::TouchAction expected_touch_action = cc::TouchAction::kPan;
GetTouchActionsForChild(router, rwhv_root, rwhv_child, point_inside_child,
effective_touch_action, allowed_touch_action);
if (allowed_touch_action.has_value())
EXPECT_EQ(expected_touch_action, allowed_touch_action.value());
EXPECT_TRUE(ExecJs(shell(), "document.body.style.touchAction = 'auto'"));
EXPECT_TRUE(ExecJs(
parent,
"document.getElementById('parent-div').style.touchAction = 'none';"));
WaitForTouchActionUpdated(root_thread_observer.get(),
child_thread_observer.get());
GetTouchActionsForChild(router, rwhv_root, rwhv_child, point_inside_child,
effective_touch_action, allowed_touch_action);
if (allowed_touch_action.has_value())
EXPECT_EQ(expected_touch_action, allowed_touch_action.value());
EXPECT_TRUE(ExecJs(
parent,
"document.getElementById('parent-div').style.touchAction = 'auto'"));
WaitForTouchActionUpdated(root_thread_observer.get(),
child_thread_observer.get());
expected_touch_action = cc::TouchAction::kAuto;
GetTouchActionsForChild(router, rwhv_root, rwhv_child, point_inside_child,
effective_touch_action, allowed_touch_action);
if (allowed_touch_action.has_value())
EXPECT_EQ(expected_touch_action, allowed_touch_action.value());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTouchActionTest,
EffectiveTouchActionPropagatesWhenChildFrameNavigates) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child = root->child_at(0);
GURL b_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(child, b_url));
EXPECT_EQ(
" Site A ------------ proxies for B\n"
" +--Site B ------- proxies for A\n"
"Where A = http://a.com/\n"
" B = http://b.com/",
DepictFrameTree(root));
RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
root->current_frame_host()->GetRenderWidgetHost()->GetView());
RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
child->current_frame_host()->GetRenderWidgetHost()->GetView());
std::unique_ptr<MainThreadFrameObserver> root_thread_observer(
new MainThreadFrameObserver(
root->current_frame_host()->GetRenderWidgetHost()));
root_thread_observer->Wait();
EXPECT_TRUE(ExecJs(shell(), "document.body.style.touchAction = 'none'"));
WaitForHitTestData(child->current_frame_host());
std::unique_ptr<MainThreadFrameObserver> child_thread_observer(
new MainThreadFrameObserver(
child->current_frame_host()->GetRenderWidgetHost()));
RenderWidgetHostViewChildFrame* child_view =
static_cast<RenderWidgetHostViewChildFrame*>(
child->current_frame_host()->GetRenderWidgetHost()->GetView());
gfx::Point point_inside_child = gfx::ToFlooredPoint(
child_view->TransformPointToRootCoordSpaceF(gfx::PointF(+5.f, +5.f)));
RenderWidgetHostInputEventRouter* router =
static_cast<WebContentsImpl*>(web_contents())->GetInputEventRouter();
WaitForTouchActionUpdated(root_thread_observer.get(),
child_thread_observer.get());
absl::optional<cc::TouchAction> effective_touch_action;
absl::optional<cc::TouchAction> allowed_touch_action;
cc::TouchAction expected_touch_action =
cc::TouchAction::kPan | cc::TouchAction::kInternalPanXScrolls |
cc::TouchAction::kInternalNotWritable;
GetTouchActionsForChild(router, rwhv_root, rwhv_child, point_inside_child,
effective_touch_action, allowed_touch_action);
if (allowed_touch_action.has_value())
EXPECT_EQ(expected_touch_action, allowed_touch_action.value());
GURL new_url(embedded_test_server()->GetURL("c.com", "/title2.html"));
child_thread_observer.reset();
EXPECT_TRUE(NavigateToURLFromRenderer(child, new_url));
WaitForHitTestData(child->current_frame_host());
child_thread_observer = std::make_unique<MainThreadFrameObserver>(
child->current_frame_host()->GetRenderWidgetHost());
rwhv_child = static_cast<RenderWidgetHostViewBase*>(
child->current_frame_host()->GetRenderWidgetHost()->GetView());
WaitForTouchActionUpdated(root_thread_observer.get(),
child_thread_observer.get());
GetTouchActionsForChild(router, rwhv_root, rwhv_child, point_inside_child,
effective_touch_action, allowed_touch_action);
if (allowed_touch_action.has_value())
EXPECT_EQ(expected_touch_action, allowed_touch_action.value());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
ChildFrameCrashMetrics_KilledMainFrame) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a(b(b,c)))"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
base::HistogramTester histograms;
RenderProcessHost* child_process = root->current_frame_host()->GetProcess();
RenderProcessHostWatcher crash_observer(
child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
child_process->Shutdown(0);
crash_observer.Wait();
histograms.ExpectTotalCount("Stability.ChildFrameCrash.Visibility", 0);
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
ChildFrameCrashMetrics_NeverShown) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b(b,c),b,b,b,b,b,b,b,b,b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
web_contents()->UpdateWebContentsVisibility(Visibility::VISIBLE);
web_contents()->UpdateWebContentsVisibility(Visibility::HIDDEN);
base::HistogramTester histograms;
RenderProcessHost* child_process =
root->child_at(0)->current_frame_host()->GetProcess();
RenderProcessHostWatcher crash_observer(
child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
child_process->Shutdown(0);
crash_observer.Wait();
EXPECT_TRUE(NavigateToURL(shell(), GURL("about:blank")));
InactiveRenderFrameHostDeletionObserver inactive_rfh_deletion_observer(
web_contents());
inactive_rfh_deletion_observer.Wait();
histograms.ExpectUniqueSample("Stability.ChildFrameCrash.Visibility",
CrashVisibility::kNeverVisibleAfterCrash, 10);
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
ChildFrameCrashMetrics_ScrolledIntoView) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
std::string filling_script = R"(
var frame = document.body.querySelectorAll("iframe")[0];
for (var i = 0; i < 100; i++) {
var p = document.createElement("p");
p.innerText = "blah";
document.body.insertBefore(p, frame);
}
)";
EXPECT_TRUE(ExecJs(root, filling_script));
EXPECT_EQ(true,
EvalJsAfterLifecycleUpdate(root->current_frame_host(), "", "true"));
base::HistogramTester histograms;
RenderProcessHost* child_process =
root->child_at(0)->current_frame_host()->GetProcess();
RenderProcessHostWatcher crash_observer(
child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
child_process->Shutdown(0);
crash_observer.Wait();
histograms.ExpectTotalCount("Stability.ChildFrameCrash.Visibility", 0);
histograms.ExpectTotalCount(
"Stability.ChildFrameCrash.ShownAfterCrashingReason", 0);
std::string scrolling_script = R"(
var frame = document.body.querySelectorAll("iframe")[0];
frame.scrollIntoView();
)";
EXPECT_TRUE(ExecJs(root, scrolling_script));
EXPECT_EQ(true,
EvalJsAfterLifecycleUpdate(root->current_frame_host(), "", "true"));
histograms.ExpectUniqueSample(
"Stability.ChildFrameCrash.Visibility",
CrossProcessFrameConnector::CrashVisibility::kShownAfterCrashing, 1);
histograms.ExpectUniqueSample(
"Stability.ChildFrameCrash.ShownAfterCrashingReason",
CrossProcessFrameConnector::ShownAfterCrashingReason::
kViewportIntersection,
1);
}
class SitePerProcessAndProcessPerSiteBrowserTest
: public SitePerProcessBrowserTest {
public:
SitePerProcessAndProcessPerSiteBrowserTest() {}
SitePerProcessAndProcessPerSiteBrowserTest(
const SitePerProcessAndProcessPerSiteBrowserTest&) = delete;
SitePerProcessAndProcessPerSiteBrowserTest& operator=(
const SitePerProcessAndProcessPerSiteBrowserTest&) = delete;
protected:
void SetUpCommandLine(base::CommandLine* command_line) override {
SitePerProcessBrowserTestBase::SetUpCommandLine(command_line);
command_line->AppendSwitch(switches::kProcessPerSite);
}
};
IN_PROC_BROWSER_TEST_P(SitePerProcessAndProcessPerSiteBrowserTest,
GeneratedTransitionsSwapProcesses) {
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL("foo.com", "/title1.html")));
scoped_refptr<SiteInstance> foo_site_instance(
web_contents()->GetSiteInstance());
TestNavigationObserver observer(web_contents());
NavigationController::LoadURLParams params(
embedded_test_server()->GetURL("bar.com", "/title2.html"));
params.transition_type = ui::PAGE_TRANSITION_GENERATED;
web_contents()->GetController().LoadURLWithParams(params);
observer.Wait();
EXPECT_NE(foo_site_instance, web_contents()->GetSiteInstance());
EXPECT_TRUE(ExecJs(web_contents(), "document.cookie = 'foo=bar';"));
EXPECT_EQ("foo=bar", EvalJs(web_contents(), "document.cookie;"));
}
namespace {
class SameDocumentCommitObserver : public WebContentsObserver {
public:
explicit SameDocumentCommitObserver(WebContents* web_contents)
: WebContentsObserver(web_contents) {
EXPECT_TRUE(web_contents);
}
SameDocumentCommitObserver(const SameDocumentCommitObserver&) = delete;
SameDocumentCommitObserver& operator=(const SameDocumentCommitObserver&) =
delete;
void Wait() { run_loop_.Run(); }
const GURL& last_committed_url() { return last_committed_url_; }
private:
void DidFinishNavigation(NavigationHandle* navigation_handle) override {
if (navigation_handle->IsSameDocument()) {
last_committed_url_ = navigation_handle->GetURL();
run_loop_.Quit();
}
}
GURL last_committed_url_;
base::RunLoop run_loop_;
};
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
ReplaceStateDoesNotCancelCrossSiteNavigation) {
GURL url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
EXPECT_TRUE(ExecJs(root,
"window.onbeforeunload = function (e) {"
" setTimeout(() => {"
" history.replaceState({}, 'footitle', 'foo');"
" }, 0);"
"};\n"));
GURL url2 = embedded_test_server()->GetURL("b.com", "/title1.html");
TestNavigationManager cross_site_navigation(web_contents(), url2);
SameDocumentCommitObserver replace_state_observer(web_contents());
EXPECT_TRUE(ExecJs(root, JsReplace("location.href = $1", url2)));
EXPECT_TRUE(cross_site_navigation.WaitForRequestStart());
replace_state_observer.Wait();
GURL replace_state_url = embedded_test_server()->GetURL("a.com", "/foo");
EXPECT_EQ(replace_state_url, replace_state_observer.last_committed_url());
ASSERT_TRUE(root->IsLoading());
ASSERT_TRUE(root->navigation_request());
cross_site_navigation.ResumeNavigation();
ASSERT_TRUE(cross_site_navigation.WaitForNavigationFinished());
EXPECT_TRUE(cross_site_navigation.was_successful());
EXPECT_EQ(url2, web_contents()->GetLastCommittedURL());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
SameDocumentNavigationDoesNotCommitPendingFramePolicy) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* subframe = root->child_at(0);
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
subframe->pending_frame_policy().sandbox_flags);
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
subframe->effective_frame_policy().sandbox_flags);
EXPECT_TRUE(ExecJs(
root, "document.querySelector('iframe').sandbox = 'allow-scripts';"));
network::mojom::WebSandboxFlags expected_flags =
network::mojom::WebSandboxFlags::kAll &
~network::mojom::WebSandboxFlags::kScripts &
~network::mojom::WebSandboxFlags::kAutomaticFeatures;
EXPECT_EQ(expected_flags, subframe->pending_frame_policy().sandbox_flags);
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
subframe->effective_frame_policy().sandbox_flags);
SameDocumentCommitObserver replace_state_observer(web_contents());
EXPECT_TRUE(ExecJs(subframe, "history.replaceState({}, 'footitle', 'foo');"));
replace_state_observer.Wait();
EXPECT_EQ(expected_flags, subframe->pending_frame_policy().sandbox_flags);
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
subframe->effective_frame_policy().sandbox_flags);
GURL fragment_url = GURL(subframe->current_url().spec() + "#foo");
{
SameDocumentCommitObserver fragment_observer(web_contents());
EXPECT_TRUE(ExecJs(subframe, JsReplace("location.href=$1", fragment_url)));
fragment_observer.Wait();
EXPECT_EQ(fragment_url, subframe->current_url());
}
EXPECT_EQ(expected_flags, subframe->pending_frame_policy().sandbox_flags);
EXPECT_EQ(network::mojom::WebSandboxFlags::kNone,
subframe->effective_frame_policy().sandbox_flags);
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
TwoBlobURLsWithNullOriginDontShareProcess) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/navigation_controller/page_with_data_iframe.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* subframe = root->child_at(0);
TestNavigationObserver observer(shell()->web_contents());
std::string blob_script =
"var blob = new Blob(['foo'], {type : 'text/html'});"
"var url = URL.createObjectURL(blob);"
"location = url;";
EXPECT_TRUE(ExecJs(subframe, blob_script));
observer.Wait();
RenderFrameHostImpl* subframe_rfh = subframe->current_frame_host();
EXPECT_TRUE(subframe_rfh->GetLastCommittedURL().SchemeIsBlob());
GURL popup_url(embedded_test_server()->GetURL(
"b.com", "/navigation_controller/page_with_data_iframe.html"));
Shell* new_shell = OpenPopup(root, popup_url, "");
FrameTreeNode* popup_root =
static_cast<WebContentsImpl*>(new_shell->web_contents())
->GetPrimaryFrameTree()
.root();
FrameTreeNode* popup_subframe = popup_root->child_at(0);
TestNavigationObserver popup_observer(new_shell->web_contents());
EXPECT_TRUE(ExecJs(popup_subframe, blob_script));
popup_observer.Wait();
RenderFrameHostImpl* popup_subframe_rfh =
popup_subframe->current_frame_host();
EXPECT_TRUE(popup_subframe_rfh->GetLastCommittedURL().SchemeIsBlob());
EXPECT_NE(subframe->current_frame_host()->GetSiteInstance(),
popup_subframe->current_frame_host()->GetSiteInstance());
EXPECT_NE(
subframe->current_frame_host()->GetSiteInstance()->GetProcess(),
popup_subframe->current_frame_host()->GetSiteInstance()->GetProcess());
EXPECT_NE(
subframe->current_frame_host()->GetSiteInstance()->GetSiteURL(),
popup_subframe->current_frame_host()->GetSiteInstance()->GetSiteURL());
}
#if BUILDFLAG(IS_FUCHSIA)
#define MAYBE_RenderFrameProxyNotRecreatedDuringProcessShutdown \
DISABLED_RenderFrameProxyNotRecreatedDuringProcessShutdown
#else
#define MAYBE_RenderFrameProxyNotRecreatedDuringProcessShutdown \
RenderFrameProxyNotRecreatedDuringProcessShutdown
#endif
IN_PROC_BROWSER_TEST_P(
SitePerProcessBrowserTest,
MAYBE_RenderFrameProxyNotRecreatedDuringProcessShutdown) {
GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
GURL popup_url(embedded_test_server()->GetURL(
"b.com", "/title1.html"));
Shell* new_shell = OpenPopup(root, popup_url, "foo");
FrameTreeNode* popup_root =
static_cast<WebContentsImpl*>(new_shell->web_contents())
->GetPrimaryFrameTree()
.root();
auto* rfh = popup_root->current_frame_host();
rfh->DisableUnloadTimerForTesting();
RenderProcessHostWatcher b_process_observer(
popup_root->current_frame_host()->GetProcess(),
RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
GURL hung_b_url(embedded_test_server()->GetURL("b.com", "/hung"));
TestNavigationManager manager(new_shell->web_contents(), hung_b_url);
EXPECT_TRUE(ExecJs(shell(), JsReplace(R"(
window.done = false;
window.onmessage = () => {
if (!window.done) {
window.open($1, 'foo');
window.done = true;
}
};)",
hung_b_url)));
EXPECT_TRUE(ExecJs(new_shell, R"(
window.onunload = () => {
for (var i=0; i<10000; i++)
opener.postMessage('hi','*');
})"));
TestFrameNavigationObserver commit_observer(popup_root);
GURL another_a_url(embedded_test_server()->GetURL("a.com", "/title3.html"));
EXPECT_TRUE(ExecJs(new_shell, JsReplace("location = $1", another_a_url)));
commit_observer.WaitForCommit();
EXPECT_TRUE(rfh->IsPendingDeletion());
EXPECT_TRUE(manager.WaitForRequestStart());
popup_root->ResetNavigationRequest(NavigationDiscardReason::kCancelled);
b_process_observer.Wait();
EXPECT_TRUE(b_process_observer.did_exit_normally());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
CommitTimeoutForHungRenderer) {
GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), a_url));
RenderProcessHost* a_process =
shell()->web_contents()->GetPrimaryMainFrame()->GetProcess();
GURL b_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
Shell* new_shell = OpenPopup(shell()->web_contents(), b_url, "newtab");
WebContents* new_contents = new_shell->web_contents();
EXPECT_TRUE(WaitForLoadStop(new_contents));
RenderProcessHost* b_process =
new_contents->GetPrimaryMainFrame()->GetProcess();
EXPECT_NE(a_process, b_process);
const char* kHungScript = "setTimeout(function() { for (;;) {}; }, 0);";
EXPECT_TRUE(ExecJs(shell()->web_contents(), kHungScript));
NavigationRequest::SetCommitTimeoutForTesting(base::Milliseconds(100));
GURL hung_url(embedded_test_server()->GetURL("a.com", "/title3.html"));
UnresponsiveRendererObserver unresponsive_renderer_observer(new_contents);
EXPECT_TRUE(
ExecJs(new_contents, JsReplace("window.location = $1", hung_url)));
RenderProcessHost* hung_process = unresponsive_renderer_observer.Wait();
EXPECT_EQ(hung_process, a_process);
NavigationRequest::SetCommitTimeoutForTesting(base::TimeDelta());
}
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS_LACROS)
#define MAYBE_NoCommitTimeoutForInvisibleWebContents \
DISABLED_NoCommitTimeoutForInvisibleWebContents
#else
#define MAYBE_NoCommitTimeoutForInvisibleWebContents \
NoCommitTimeoutForInvisibleWebContents
#endif
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
MAYBE_NoCommitTimeoutForInvisibleWebContents) {
GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), a_url));
RenderProcessHost* a_process =
shell()->web_contents()->GetPrimaryMainFrame()->GetProcess();
GURL b_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
Shell* new_shell = OpenPopup(shell()->web_contents(), b_url, "newtab");
WebContents* new_contents = new_shell->web_contents();
EXPECT_TRUE(WaitForLoadStop(new_contents));
RenderProcessHost* b_process =
new_contents->GetPrimaryMainFrame()->GetProcess();
EXPECT_NE(a_process, b_process);
const char* kHungScript = "setTimeout(function() { for (;;) {}; }, 0);";
EXPECT_TRUE(ExecJs(shell()->web_contents(), kHungScript));
new_contents->WasHidden();
EXPECT_EQ(Visibility::HIDDEN, new_contents->GetVisibility());
base::TimeDelta kTimeout = base::Milliseconds(100);
NavigationRequest::SetCommitTimeoutForTesting(kTimeout);
GURL hung_url(embedded_test_server()->GetURL("a.com", "/title3.html"));
UnresponsiveRendererObserver unresponsive_renderer_observer(new_contents);
EXPECT_TRUE(
ExecJs(new_contents, JsReplace("window.location = $1", hung_url)));
RenderProcessHost* hung_process =
unresponsive_renderer_observer.Wait(kTimeout * 10);
EXPECT_FALSE(hung_process);
NavigationRequest::SetCommitTimeoutForTesting(base::TimeDelta());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, ProcessSwapOnInnerContents) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* child_frame =
web_contents()->GetPrimaryFrameTree().root()->child_at(0);
WebContentsImpl* inner_contents =
static_cast<WebContentsImpl*>(CreateAndAttachInnerContents(
ToRenderFrameHost(child_frame).render_frame_host()));
FrameTreeNode* inner_contents_root =
inner_contents->GetPrimaryFrameTree().root();
RenderFrameProxyHost* outer_proxy =
inner_contents_root->render_manager()->GetProxyToOuterDelegate();
CrossProcessFrameConnector* outer_connector =
outer_proxy->cross_process_frame_connector();
EXPECT_NE(nullptr, outer_connector->get_view_for_testing());
GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(inner_contents_root, a_url));
SiteInstance* a_site_instance =
inner_contents->GetPrimaryMainFrame()->GetSiteInstance();
RenderProcessHost* a_process = a_site_instance->GetProcess();
RenderWidgetHostViewChildFrame* a_view =
outer_connector->get_view_for_testing();
GURL b_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(inner_contents_root, b_url));
SiteInstance* b_site_instance =
inner_contents->GetPrimaryMainFrame()->GetSiteInstance();
RenderProcessHost* b_process = b_site_instance->GetProcess();
RenderWidgetHostViewChildFrame* b_view =
outer_connector->get_view_for_testing();
EXPECT_NE(a_site_instance, b_site_instance);
EXPECT_NE(a_process, b_process);
EXPECT_NE(nullptr, a_view);
EXPECT_NE(nullptr, b_view);
EXPECT_NE(a_view, b_view);
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, FocusInnerContentsFromOOPIF) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* child_frame =
web_contents()->GetPrimaryFrameTree().root()->child_at(0);
WebContentsImpl* inner_contents =
static_cast<WebContentsImpl*>(CreateAndAttachInnerContents(
ToRenderFrameHost(child_frame).render_frame_host()));
FrameTreeNode* inner_contents_root =
inner_contents->GetPrimaryFrameTree().root();
GURL b_url(embedded_test_server()->GetURL(
"b.com", "/cross_site_iframe_factory.html?b(b)"));
EXPECT_TRUE(NavigateToURLFromRenderer(inner_contents_root, b_url));
GURL c_url(embedded_test_server()->GetURL("c.com", "/title1.html"));
FrameTreeNode* inner_child = inner_contents_root->child_at(0);
EXPECT_TRUE(NavigateToURLFromRenderer(inner_child, c_url));
EXPECT_NE(inner_contents_root->current_frame_host()->GetSiteInstance(),
inner_child->current_frame_host()->GetSiteInstance());
EXPECT_TRUE(inner_child->current_frame_host()->IsCrossProcessSubframe());
web_contents()->Focus();
web_contents()->SetAsFocusedWebContentsIfNecessary();
EXPECT_EQ(web_contents(), web_contents()->GetFocusedWebContents());
inner_contents->FocusOwningWebContents(
inner_child->current_frame_host()->GetRenderWidgetHost());
EXPECT_EQ(inner_contents, web_contents()->GetFocusedWebContents());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
FileURLBlockedWithConsoleErrorInRemoteFrameNavigation) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* child =
web_contents()->GetPrimaryFrameTree().root()->child_at(0);
GURL original_frame_url(child->current_frame_host()->GetLastCommittedURL());
EXPECT_EQ("b.com", original_frame_url.host());
WebContentsConsoleObserver console_observer(web_contents());
console_observer.SetPattern("Not allowed to load local resource: file:*");
GURL file_url("file:///");
EXPECT_TRUE(
ExecJs(web_contents(),
JsReplace("document.querySelector('iframe').src = $1", file_url)));
ASSERT_TRUE(console_observer.Wait());
EXPECT_EQ(original_frame_url,
child->current_frame_host()->GetLastCommittedURL());
}
#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_ANDROID)
class DoubleTapZoomContentBrowserClient
: public ContentBrowserTestContentBrowserClient {
public:
DoubleTapZoomContentBrowserClient() = default;
DoubleTapZoomContentBrowserClient(const DoubleTapZoomContentBrowserClient&) =
delete;
DoubleTapZoomContentBrowserClient& operator=(
const DoubleTapZoomContentBrowserClient&) = delete;
void OverrideWebkitPrefs(
content::WebContents* web_contents,
blink::web_pref::WebPreferences* web_prefs) override {
web_prefs->double_tap_to_zoom_enabled = true;
}
};
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
TouchscreenAnimateDoubleTapZoomInOOPIF) {
DoubleTapZoomContentBrowserClient content_browser_client;
web_contents()->OnWebPreferencesChanged();
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
ASSERT_EQ(1u, root->child_count());
FrameTreeNode* child_b = root->child_at(0);
ASSERT_TRUE(child_b);
RenderFrameSubmissionObserver observer_a(root);
observer_a.WaitForAnyFrameSubmission();
float original_page_scale =
observer_a.LastRenderFrameMetadata().page_scale_factor;
WaitForHitTestData(child_b->current_frame_host());
gfx::PointF tap_position =
child_b->current_frame_host()
->GetRenderWidgetHost()
->GetView()
->TransformPointToRootCoordSpaceF(gfx::PointF(10, 10));
std::string actions_template = R"HTML(
[{
"source" : "touch",
"actions" : [
{ "name": "pointerDown", "x": %f, "y": %f},
{ "name": "pointerUp"},
{ "name": "pause", "duration": 50 },
{ "name": "pointerDown", "x": %f, "y": %f},
{ "name": "pointerUp"}
]
}]
)HTML";
std::string double_tap_actions_json =
base::StringPrintf(actions_template.c_str(), tap_position.x(),
tap_position.y(), tap_position.x(), tap_position.y());
auto parsed_json =
base::JSONReader::ReadAndReturnValueWithError(double_tap_actions_json);
ASSERT_TRUE(parsed_json.has_value()) << parsed_json.error().message;
ActionsParser actions_parser(std::move(*parsed_json));
ASSERT_TRUE(actions_parser.Parse());
auto synthetic_gesture_doubletap =
SyntheticGesture::Create(actions_parser.gesture_params());
InputEventAckWaiter ack_waiter(
child_b->current_frame_host()->GetRenderWidgetHost(),
blink::WebInputEvent::Type::kGestureDoubleTap);
auto* host = static_cast<RenderWidgetHostImpl*>(
root->current_frame_host()->GetRenderWidgetHost());
host->QueueSyntheticGesture(
std::move(synthetic_gesture_doubletap),
base::BindOnce([](SyntheticGesture::Result result) {
EXPECT_EQ(SyntheticGesture::GESTURE_FINISHED, result);
}));
ack_waiter.Wait();
float target_scale = 1.1f * original_page_scale;
float new_page_scale = original_page_scale;
do {
observer_a.WaitForAnyFrameSubmission();
new_page_scale = observer_a.LastRenderFrameMetadata().page_scale_factor;
} while (new_page_scale < target_scale);
}
#endif
class CrossProcessNavigationObjectElementTest
: public SitePerProcessBrowserTestBase,
public testing::WithParamInterface<
std::tuple<std::string, std::string, std::string>> {};
IN_PROC_BROWSER_TEST_P(CrossProcessNavigationObjectElementTest, FallbackShown) {
const GURL main_url = embedded_test_server()->GetURL(
base::StringPrintf("%s.com", std::get<0>(GetParam()).c_str()),
"/page_with_object_fallback.html");
const GURL object_valid_url = embedded_test_server()->GetURL(
base::StringPrintf("%s.com", std::get<1>(GetParam()).c_str()),
"/title1.html");
const GURL object_invalid_url = embedded_test_server()->GetURL(
base::StringPrintf("%s.com", std::get<2>(GetParam()).c_str()),
"/does-not-exist-throws-404.html");
ASSERT_TRUE(NavigateToURL(shell(), main_url));
ASSERT_EQ("OBJECT_LOAD",
EvalJs(web_contents(), JsReplace("setUrl($1);", object_valid_url)));
ASSERT_EQ(false, EvalJs(web_contents(), "fallbackVisible()"));
ASSERT_EQ(true, EvalJs(web_contents(), JsReplace("setUrl($1);"
"notifyWhenFallbackShown();",
object_invalid_url)));
}
INSTANTIATE_TEST_SUITE_P(SitePerProcess,
CrossProcessNavigationObjectElementTest,
testing::Values(std::make_tuple("a", "a", "b"),
std::make_tuple("a", "b", "b"),
std::make_tuple("a", "b", "c")));
#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
DISABLED_OccludedRenderWidgetThrottlesRAF) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* subframe = root->child_at(0);
GURL page_with_raf_counter =
embedded_test_server()->GetURL("a.com", "/page_with_raf_counter.html");
EXPECT_TRUE(NavigateToURLFromRenderer(subframe, page_with_raf_counter));
auto allow_time_for_rafs = []() {
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE, run_loop.QuitClosure(), base::Milliseconds(1000));
run_loop.Run();
};
ASSERT_TRUE(ExecJs(subframe, "reset_count();"));
allow_time_for_rafs();
int32_t default_raf_count = EvalJs(subframe, "raf_count").ExtractInt();
EXPECT_GT(default_raf_count, 5);
web_contents()->WasOccluded();
ASSERT_TRUE(ExecJs(subframe, "reset_count();"));
allow_time_for_rafs();
int32_t raf_count = EvalJs(subframe, "raf_count").ExtractInt();
EXPECT_EQ(raf_count, 0);
web_contents()->WasShown();
ASSERT_TRUE(ExecJs(subframe, "reset_count();"));
allow_time_for_rafs();
raf_count = EvalJs(subframe, "raf_count").ExtractInt();
EXPECT_GT(raf_count, 5);
}
#endif
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
CommittedOriginIncompatibleWithOriginLock) {
GURL start_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), start_url));
FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryFrameTree()
.root();
GURL another_url(embedded_test_server()->GetURL("a.com", "/title2.html"));
const GURL bad_url = GURL("https://b.com");
auto process_lock =
root->current_frame_host()->GetProcess()->GetProcessLock();
IsolationContext isolation_context(
shell()->web_contents()->GetBrowserContext());
ProcessLock start_url_lock = ProcessLock::FromSiteInfo(
SiteInfo::CreateForTesting(isolation_context, start_url));
ProcessLock another_url_lock = ProcessLock::FromSiteInfo(
SiteInfo::CreateForTesting(isolation_context, another_url));
ProcessLock bad_url_lock = ProcessLock::FromSiteInfo(
SiteInfo::CreateForTesting(isolation_context, bad_url));
EXPECT_EQ(start_url_lock, process_lock);
EXPECT_EQ(another_url_lock, process_lock);
EXPECT_NE(bad_url_lock, process_lock);
PwnCommitIPC(shell()->web_contents(), another_url, another_url,
url::Origin::Create(bad_url));
EXPECT_TRUE(
BeginNavigateToURLFromRenderer(shell()->web_contents(), another_url));
RenderProcessHostBadIpcMessageWaiter kill_waiter(
root->current_frame_host()->GetProcess());
EXPECT_EQ(bad_message::RFH_INVALID_ORIGIN_ON_COMMIT, kill_waiter.Wait());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
PluginElementResponsiveInCrossProcessNavigations) {
GURL main_frame_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
ASSERT_TRUE(NavigateToURL(shell(), main_frame_url));
GURL cross_origin(embedded_test_server()->GetURL("b.com", "/title1.html"));
std::string msg =
EvalJs(shell(), JsReplace("var object = document.createElement('object');"
"document.body.appendChild(object);"
"object.data = $1;"
"object.type='text/html';"
"object.notify = true;"
"new Promise(resolve => {"
" object.onload = () => {"
" if (!object.notify) return;"
" object.notify = false;"
" resolve('done');"
" };"
"});",
cross_origin))
.ExtractString();
ASSERT_EQ("done", msg);
auto* frame_connector = web_contents()
->GetPrimaryFrameTree()
.root()
->child_at(0)
->render_manager()
->GetProxyToParent()
->cross_process_frame_connector();
ASSERT_FALSE(frame_connector->IsHidden());
ASSERT_TRUE(ExecJs(
shell(), "document.querySelector('object').style.display = 'none';"));
while (!frame_connector->IsHidden()) {
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
run_loop.Run();
}
ASSERT_TRUE(ExecJs(
shell(), "document.querySelector('object').style.display = 'block';"));
while (frame_connector->IsHidden()) {
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
run_loop.Run();
}
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
NavigationCommitInIframePendingDeletionAB) {
GURL url_a(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
GURL url_c(embedded_test_server()->GetURL("c.com", "/hung"));
EXPECT_TRUE(NavigateToURL(shell(), url_a));
RenderFrameHostImpl* rfh_a = web_contents()->GetPrimaryMainFrame();
RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
rfh_b->DoNotDeleteForTesting();
EXPECT_TRUE(ExecJs(rfh_b, "onunload=function(){}"));
TestNavigationManager navigation_observer(web_contents(), url_c);
EXPECT_TRUE(ExecJs(rfh_b, JsReplace("location.href=$1;", url_c)));
EXPECT_TRUE(navigation_observer.WaitForRequestStart());
RenderFrameHostImpl* rfh_c =
rfh_b->frame_tree_node()->render_manager()->speculative_frame_host();
EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kActive,
rfh_a->lifecycle_state());
EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kActive,
rfh_b->lifecycle_state());
EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kSpeculative,
rfh_c->lifecycle_state());
RenderFrameDeletedObserver delete_b(rfh_b), delete_c(rfh_c);
EXPECT_TRUE(
ExecJs(rfh_a, JsReplace("document.querySelector('iframe').remove();")));
EXPECT_FALSE(delete_b.deleted());
EXPECT_TRUE(delete_c.deleted());
EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kActive,
rfh_a->lifecycle_state());
EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kRunningUnloadHandlers,
rfh_b->lifecycle_state());
ASSERT_TRUE(navigation_observer.WaitForNavigationFinished());
EXPECT_FALSE(navigation_observer.was_successful());
EXPECT_FALSE(delete_b.deleted());
rfh_b->DetachForTesting();
EXPECT_TRUE(delete_b.deleted());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
NavigationCommitInIframePendingDeletionABC) {
GURL url_a(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b(c))"));
GURL url_d(embedded_test_server()->GetURL("d.com", "/hung"));
EXPECT_TRUE(NavigateToURL(shell(), url_a));
RenderFrameHostImpl* rfh_a = web_contents()->GetPrimaryMainFrame();
RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
RenderFrameHostImpl* rfh_c = rfh_b->child_at(0)->current_frame_host();
LeaveInPendingDeletionState(rfh_c);
TestNavigationManager navigation_observer(web_contents(), url_d);
EXPECT_TRUE(ExecJs(rfh_c, JsReplace("location.href=$1;", url_d)));
EXPECT_TRUE(navigation_observer.WaitForRequestStart());
RenderFrameHostImpl* rfh_d =
rfh_c->frame_tree_node()->render_manager()->speculative_frame_host();
EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kActive,
rfh_a->lifecycle_state());
EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kActive,
rfh_b->lifecycle_state());
EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kActive,
rfh_c->lifecycle_state());
EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kSpeculative,
rfh_d->lifecycle_state());
RenderFrameDeletedObserver delete_b(rfh_b), delete_c(rfh_c), delete_d(rfh_d);
EXPECT_TRUE(
ExecJs(rfh_a, JsReplace("document.querySelector('iframe').remove();")));
EXPECT_FALSE(delete_b.deleted());
EXPECT_FALSE(delete_c.deleted());
EXPECT_TRUE(delete_d.deleted());
EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kActive,
rfh_a->lifecycle_state());
EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kReadyToBeDeleted,
rfh_b->lifecycle_state());
EXPECT_EQ(RenderFrameHost::LifecycleState::kPendingDeletion,
rfh_b->GetLifecycleState());
EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kRunningUnloadHandlers,
rfh_c->lifecycle_state());
EXPECT_EQ(RenderFrameHost::LifecycleState::kPendingDeletion,
rfh_c->GetLifecycleState());
ASSERT_TRUE(navigation_observer.WaitForNavigationFinished());
EXPECT_FALSE(navigation_observer.was_successful());
EXPECT_FALSE(delete_b.deleted());
EXPECT_FALSE(delete_c.deleted());
rfh_c->DetachForTesting();
EXPECT_TRUE(delete_b.deleted());
EXPECT_TRUE(delete_c.deleted());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
SameDocumentCommitWhilePendingDeletion) {
GURL url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), url));
RenderFrameHostImpl* rfh_a = web_contents()->GetPrimaryMainFrame();
RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
EXPECT_TRUE(ExecJs(rfh_b, "onunload=function(){}"));
RenderFrameDeletedObserver deleted_observer(rfh_b);
DidStartNavigationObserver did_start_navigation_observer(web_contents());
ExecuteScriptAsync(rfh_b, "location.href='#fragment'");
rfh_b->DetachFromProxy();
deleted_observer.WaitUntilDeleted();
EXPECT_FALSE(did_start_navigation_observer.observed());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
HistoryNavigationWhilePendingDeletion) {
GURL url_ab(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_ab));
RenderFrameHostImpl* rfh_a = web_contents()->GetPrimaryMainFrame();
RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
EXPECT_TRUE(NavigateToURLFromRenderer(rfh_b->frame_tree_node(), url_c));
RenderFrameHostImpl* rfh_c = rfh_a->child_at(0)->current_frame_host();
EXPECT_TRUE(ExecJs(rfh_a, "window.foo='bar';"));
EXPECT_TRUE(ExecJs(rfh_c, "onunload=function(){}"));
RenderFrameDeletedObserver deleted_observer(rfh_c);
ExecuteScriptAsync(rfh_c, "history.back();");
rfh_c->DetachFromProxy();
deleted_observer.WaitUntilDeleted();
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ("bar", EvalJs(rfh_a, "window.foo"));
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
OpenUrlToRemoteFramePendingDeletion) {
GURL url_ab(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), url_ab));
RenderFrameHostImpl* rfh_a = web_contents()->GetPrimaryMainFrame();
RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
EXPECT_TRUE(ExecJs(rfh_b, "onunload=function(){}"));
RenderFrameDeletedObserver deleted_observer(rfh_b);
DidStartNavigationObserver did_start_navigation_observer(web_contents());
EXPECT_TRUE(ExecJs(rfh_b, "window.name = 'name';"));
ExecuteScriptAsync(rfh_a, JsReplace("window.open($1, 'name');", url_c));
rfh_b->DetachFromProxy();
deleted_observer.WaitUntilDeleted();
EXPECT_FALSE(did_start_navigation_observer.observed());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
ProcessDiesBeforeCrossSiteNavigationCompletes) {
GURL first_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), first_url));
scoped_refptr<SiteInstanceImpl> first_site_instance(
web_contents()->GetPrimaryMainFrame()->GetSiteInstance());
GURL second_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
TestNavigationManager delayer(web_contents(), second_url);
web_contents()->GetController().LoadURL(
second_url, Referrer(), ui::PageTransition::PAGE_TRANSITION_TYPED,
std::string());
EXPECT_TRUE(delayer.WaitForRequestStart());
RenderProcessHost* first_process =
web_contents()->GetPrimaryMainFrame()->GetProcess();
RenderProcessHostWatcher crash_observer(
first_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
EXPECT_TRUE(first_process->Shutdown(0));
crash_observer.Wait();
EXPECT_FALSE(web_contents()->GetPrimaryMainFrame()->IsRenderFrameLive());
ASSERT_TRUE(delayer.WaitForNavigationFinished());
EXPECT_TRUE(web_contents()->GetPrimaryMainFrame()->IsRenderFrameLive());
EXPECT_NE(web_contents()->GetPrimaryMainFrame()->GetProcess(), first_process);
EXPECT_NE(web_contents()->GetPrimaryMainFrame()->GetSiteInstance(),
first_site_instance);
EXPECT_EQ(second_url,
web_contents()->GetPrimaryMainFrame()->GetLastCommittedURL());
}
enum class InnerWebContentsAttachChildFrameOriginType {
kSameOriginAboutBlank,
kSameOriginOther,
kCrossOrigin
};
class InnerWebContentsAttachTest
: public SitePerProcessBrowserTestBase,
public testing::WithParamInterface<
std::tuple<InnerWebContentsAttachChildFrameOriginType,
bool /* original frame has beforeunload handlers */,
bool /* user proceeds with attaching */>> {
public:
InnerWebContentsAttachTest() {}
InnerWebContentsAttachTest(const InnerWebContentsAttachTest&) = delete;
InnerWebContentsAttachTest& operator=(const InnerWebContentsAttachTest&) =
delete;
~InnerWebContentsAttachTest() override {}
protected:
class PrepareFrameJob {
public:
PrepareFrameJob(RenderFrameHostImpl* original_render_frame_host,
bool proceed_through_beforeunload) {
auto* web_contents =
WebContents::FromRenderFrameHost(original_render_frame_host);
PrepContentsForBeforeUnloadTest(web_contents);
SetShouldProceedOnBeforeUnload(Shell::FromWebContents(web_contents),
true ,
proceed_through_beforeunload);
RenderFrameHost::PrepareForInnerWebContentsAttachCallback callback =
base::BindOnce(&PrepareFrameJob::OnPrepare, base::Unretained(this));
original_render_frame_host->PrepareForInnerWebContentsAttach(
std::move(callback));
}
PrepareFrameJob(const PrepareFrameJob&) = delete;
PrepareFrameJob& operator=(const PrepareFrameJob&) = delete;
virtual ~PrepareFrameJob() {}
void WaitForPreparedFrame() {
if (did_call_prepare_)
return;
run_loop_.Run();
}
RenderFrameHostImpl* prepared_frame() const {
return new_render_frame_host_;
}
private:
void OnPrepare(RenderFrameHost* render_frame_host) {
did_call_prepare_ = true;
new_render_frame_host_ =
static_cast<RenderFrameHostImpl*>(render_frame_host);
if (run_loop_.running())
run_loop_.Quit();
}
bool did_call_prepare_ = false;
raw_ptr<RenderFrameHostImpl> new_render_frame_host_ = nullptr;
base::RunLoop run_loop_;
};
};
IN_PROC_BROWSER_TEST_P(InnerWebContentsAttachTest, PrepareFrame) {
ASSERT_TRUE(
NavigateToURL(shell(), embedded_test_server()->GetURL(
"a.com", "/page_with_object_fallback.html")));
InnerWebContentsAttachChildFrameOriginType child_frame_origin_type =
std::get<0>(GetParam());
bool test_beforeunload = std::get<1>(GetParam());
bool proceed_through_beforeunload = std::get<2>(GetParam());
GURL child_frame_url =
child_frame_origin_type ==
InnerWebContentsAttachChildFrameOriginType::kSameOriginAboutBlank
? GURL(url::kAboutBlankURL)
: child_frame_origin_type ==
InnerWebContentsAttachChildFrameOriginType::kSameOriginOther
? embedded_test_server()->GetURL("a.com", "/title1.html")
: embedded_test_server()->GetURL("b.com", "/title1.html");
SCOPED_TRACE(testing::Message()
<< " Child frame URL:" << child_frame_url.spec()
<< " 'beforeunload' modal shown: " << test_beforeunload
<< " proceed through'beforeunload': "
<< proceed_through_beforeunload);
auto* child_node = web_contents()->GetPrimaryFrameTree().root()->child_at(0);
EXPECT_TRUE(NavigateToURLFromRenderer(child_node, child_frame_url));
if (test_beforeunload) {
EXPECT_TRUE(ExecJs(child_node,
"window.addEventListener('beforeunload', (e) => {"
"e.preventDefault(); return e; });"));
}
auto* original_child_frame = child_node->current_frame_host();
RenderFrameDeletedObserver original_child_frame_observer(
original_child_frame);
AppModalDialogWaiter dialog_waiter(shell());
PrepareFrameJob prepare_job(original_child_frame,
proceed_through_beforeunload);
if (test_beforeunload)
dialog_waiter.Wait();
prepare_job.WaitForPreparedFrame();
auto* new_render_frame_host = prepare_job.prepared_frame();
bool did_prepare_frame = new_render_frame_host;
bool same_frame_used = (new_render_frame_host == original_child_frame);
ASSERT_TRUE(did_prepare_frame ||
(test_beforeunload && !proceed_through_beforeunload));
bool is_same_origin =
child_frame_origin_type !=
InnerWebContentsAttachChildFrameOriginType::kCrossOrigin;
if (!is_same_origin && did_prepare_frame) {
original_child_frame_observer.WaitUntilDeleted();
}
ASSERT_TRUE(!did_prepare_frame || (is_same_origin == same_frame_used));
ASSERT_TRUE(!did_prepare_frame ||
(original_child_frame_observer.deleted() != is_same_origin));
if (new_render_frame_host)
CreateAndAttachInnerContents(new_render_frame_host);
}
INSTANTIATE_TEST_SUITE_P(
SitePerProcess,
InnerWebContentsAttachTest,
testing::Combine(
testing::ValuesIn(
{InnerWebContentsAttachChildFrameOriginType::kSameOriginAboutBlank,
InnerWebContentsAttachChildFrameOriginType::kSameOriginOther,
InnerWebContentsAttachChildFrameOriginType::kCrossOrigin}),
testing::Bool(),
testing::Bool()));
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
SameAndCrossProcessIframeAboutBlankNavigation) {
GURL a1_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), a1_url));
RenderFrameHostImpl* a1_rfh = web_contents()->GetPrimaryMainFrame();
RenderFrameHostImpl* b2_rfh = a1_rfh->child_at(0)->current_frame_host();
{
scoped_refptr<SiteInstance> b2_site_instance = b2_rfh->GetSiteInstance();
TestNavigationManager navigation_manager(web_contents(),
GURL("about:blank"));
EXPECT_TRUE(ExecJs(b2_rfh, "location.href = 'about:blank';"));
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
RenderFrameHostImpl* b3_rfh = a1_rfh->child_at(0)->current_frame_host();
DCHECK_EQ(b3_rfh->GetSiteInstance(), b2_site_instance);
DCHECK_NE(a1_rfh->GetProcess(), b3_rfh->GetProcess());
}
{
TestNavigationManager navigation_manager(web_contents(),
GURL("about:blank"));
EXPECT_TRUE(ExecJs(a1_rfh, R"(
document.querySelector("iframe").src = "about:blank";
)"));
ASSERT_TRUE(navigation_manager.WaitForNavigationFinished());
RenderFrameHostImpl* b4_rfh = a1_rfh->child_at(0)->current_frame_host();
DCHECK_EQ(a1_rfh->GetSiteInstance(), b4_rfh->GetSiteInstance());
}
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
AccessWindowProxyOfCrashedFrameAfterNavigation) {
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
const GURL cross_site_url =
embedded_test_server()->GetURL("b.com", "/title1.html");
TestNavigationObserver observer(cross_site_url);
observer.StartWatchingNewWebContents();
EXPECT_TRUE(ExecJs(
shell(), JsReplace("openedWindow = window.open($1)", cross_site_url)));
observer.WaitForNavigationFinished();
EXPECT_EQ(2u, Shell::windows().size());
CrashTab(Shell::windows()[1]->web_contents());
EXPECT_TRUE(
ExecJs(shell(), "openedWindow.location = 'data:text/html,content'"));
std::string result =
EvalJs(shell(),
"try { openedWindow.document } catch (e) { e.toString(); }")
.ExtractString();
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(SitePerProcessBrowserTest, CloseNoopenerWindow) {
GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
GURL popup_url(
embedded_test_server()->GetURL("a.com", "/page_with_blank_iframe.html"));
ShellAddedObserver new_shell_observer;
EXPECT_TRUE(ExecJs(
shell(),
JsReplace("popup = window.open($1,'_blank','noopener');", popup_url)));
Shell* popup = new_shell_observer.GetShell();
WebContentsImpl* popup_web_contents =
static_cast<WebContentsImpl*>(popup->web_contents());
FrameTreeNode* popup_root = popup_web_contents->GetPrimaryFrameTree().root();
EXPECT_TRUE(WaitForLoadStop(popup_web_contents));
FrameTreeNode* child = popup_root->child_at(0);
GURL cross_origin_url(
embedded_test_server()->GetURL("b.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRenderer(child, cross_origin_url));
WebContentsDestroyedWatcher destroyed_watcher(popup->web_contents());
EXPECT_TRUE(ExecJs(child, "window.parent.close()"));
destroyed_watcher.Wait();
}
IN_PROC_BROWSER_TEST_P(
SitePerProcessBrowserTest,
ProcessNotReusedAfterInitialNavigationToRendererDebugURL) {
GURL javascript_url("javascript:'foo'");
shell()->LoadURL(javascript_url);
EXPECT_EQ("foo", EvalJs(shell(), "document.body.innerText"));
RenderProcessHost* js_process =
web_contents()->GetPrimaryMainFrame()->GetProcess();
EXPECT_FALSE(js_process->IsUnused());
EXPECT_TRUE(NavigateToURL(
shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
EXPECT_NE(js_process, web_contents()->GetPrimaryMainFrame()->GetProcess());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, UserActivationCrossSite) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child = root->child_at(0);
EXPECT_FALSE(child->current_frame_host()->HasStickyUserActivation());
EXPECT_EQ(false, EvalJs(child->current_frame_host(),
"navigator.userActivation.hasBeenActive",
EXECUTE_SCRIPT_NO_USER_GESTURE));
GURL first_http_url(embedded_test_server()->GetURL("d.com", "/title1.html"));
EXPECT_TRUE(
NavigateToURLFromRendererWithoutUserGesture(child, first_http_url));
EXPECT_FALSE(child->current_frame_host()->HasStickyUserActivation());
EXPECT_EQ(false, EvalJs(child->current_frame_host(),
"navigator.userActivation.hasBeenActive",
EXECUTE_SCRIPT_NO_USER_GESTURE));
EXPECT_TRUE(ExecJs(child, "// No-op script"));
EXPECT_TRUE(child->current_frame_host()->HasStickyUserActivation());
EXPECT_EQ(true, EvalJs(child->current_frame_host(),
"navigator.userActivation.hasBeenActive",
EXECUTE_SCRIPT_NO_USER_GESTURE));
GURL http_url(embedded_test_server()->GetURL("c.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRendererWithoutUserGesture(child, http_url));
EXPECT_FALSE(child->current_frame_host()->HasStickyUserActivation());
EXPECT_EQ(false, EvalJs(child->current_frame_host(),
"navigator.userActivation.hasBeenActive",
EXECUTE_SCRIPT_NO_USER_GESTURE));
EXPECT_TRUE(ExecJs(child->current_frame_host(),
JsReplace("window.open($1, $2)", http_url, "_top"),
EXECUTE_SCRIPT_NO_USER_GESTURE));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_NE(http_url, shell()->web_contents()->GetLastCommittedURL());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, UserActivationSameSite) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child = root->child_at(0);
EXPECT_FALSE(child->current_frame_host()->HasStickyUserActivation());
EXPECT_EQ(false, EvalJs(child->current_frame_host(),
"navigator.userActivation.hasBeenActive",
EXECUTE_SCRIPT_NO_USER_GESTURE));
GURL first_http_url(
embedded_test_server()->GetURL("subdomain.b.com", "/title1.html"));
EXPECT_TRUE(
NavigateToURLFromRendererWithoutUserGesture(child, first_http_url));
EXPECT_FALSE(child->current_frame_host()->HasStickyUserActivation());
EXPECT_EQ(false, EvalJs(child->current_frame_host(),
"navigator.userActivation.hasBeenActive",
EXECUTE_SCRIPT_NO_USER_GESTURE));
EXPECT_TRUE(ExecJs(child, "// No-op script"));
EXPECT_TRUE(child->current_frame_host()->HasStickyUserActivation());
EXPECT_EQ(true, EvalJs(child->current_frame_host(),
"navigator.userActivation.hasBeenActive",
EXECUTE_SCRIPT_NO_USER_GESTURE));
GURL http_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
EXPECT_TRUE(NavigateToURLFromRendererWithoutUserGesture(child, http_url));
EXPECT_TRUE(child->current_frame_host()->HasStickyUserActivation());
EXPECT_EQ(true, EvalJs(child->current_frame_host(),
"navigator.userActivation.hasBeenActive",
EXECUTE_SCRIPT_NO_USER_GESTURE));
EXPECT_TRUE(ExecJs(child->current_frame_host(),
JsReplace("window.open($1, $2)", http_url, "_top"),
EXECUTE_SCRIPT_NO_USER_GESTURE));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(http_url, shell()->web_contents()->GetLastCommittedURL());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, UserActivationSameOrigin) {
GURL main_url(embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(b)"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child = root->child_at(0);
EXPECT_FALSE(child->current_frame_host()->HasStickyUserActivation());
EXPECT_EQ(false, EvalJs(child->current_frame_host(),
"navigator.userActivation.hasBeenActive",
EXECUTE_SCRIPT_NO_USER_GESTURE));
GURL first_http_url(embedded_test_server()->GetURL("c.com", "/title1.html"));
EXPECT_TRUE(NavigateIframeToURL(web_contents(), "child-0", first_http_url));
EXPECT_FALSE(child->current_frame_host()->HasStickyUserActivation());
EXPECT_EQ(false, EvalJs(child->current_frame_host(),
"navigator.userActivation.hasBeenActive",
EXECUTE_SCRIPT_NO_USER_GESTURE));
EXPECT_TRUE(ExecJs(child, "// No-op script"));
EXPECT_TRUE(child->current_frame_host()->HasStickyUserActivation());
EXPECT_EQ(true, EvalJs(child->current_frame_host(),
"navigator.userActivation.hasBeenActive",
EXECUTE_SCRIPT_NO_USER_GESTURE));
GURL http_url(embedded_test_server()->GetURL("c.com", "/title2.html"));
EXPECT_TRUE(NavigateIframeToURL(web_contents(), "child-0", http_url));
EXPECT_TRUE(child->current_frame_host()->HasStickyUserActivation());
EXPECT_EQ(true, EvalJs(child->current_frame_host(),
"navigator.userActivation.hasBeenActive",
EXECUTE_SCRIPT_NO_USER_GESTURE));
EXPECT_TRUE(ExecJs(child->current_frame_host(),
JsReplace("window.open($1, $2)", http_url, "_top"),
EXECUTE_SCRIPT_NO_USER_GESTURE));
EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
EXPECT_EQ(http_url, shell()->web_contents()->GetLastCommittedURL());
}
class DisableProcessReusePolicyTest : public SitePerProcessBrowserTest {
public:
DisableProcessReusePolicyTest() {
scoped_feature_list_.InitAndEnableFeature(features::kDisableProcessReuse);
}
~DisableProcessReusePolicyTest() override = default;
DisableProcessReusePolicyTest(const DisableProcessReusePolicyTest&) = delete;
DisableProcessReusePolicyTest& operator=(
const DisableProcessReusePolicyTest&) = delete;
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_P(DisableProcessReusePolicyTest,
DisableProcessReusePolicy) {
GURL url(
embedded_test_server()->GetURL("www.foo.com", "/page_with_iframe.html"));
EXPECT_TRUE(NavigateToURL(shell(), url));
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
FrameTreeNode* child = root->child_at(0);
GURL cross_site_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
TestNavigationObserver observer(shell()->web_contents());
EXPECT_TRUE(NavigateToURLFromRenderer(child, cross_site_url));
EXPECT_TRUE(child->current_frame_host()->IsCrossProcessSubframe());
Shell* second_shell = CreateBrowser();
EXPECT_TRUE(NavigateToURL(second_shell, url));
FrameTreeNode* second_root =
static_cast<WebContentsImpl*>(second_shell->web_contents())
->GetPrimaryFrameTree()
.root();
FrameTreeNode* second_child = second_root->child_at(0);
EXPECT_TRUE(NavigateToURLFromRenderer(second_child, cross_site_url));
EXPECT_TRUE(second_child->current_frame_host()->IsCrossProcessSubframe());
scoped_refptr<SiteInstanceImpl> second_shell_instance =
second_child->current_frame_host()->GetSiteInstance();
EXPECT_NE(
SiteInstanceImpl::ProcessReusePolicy::REUSE_PENDING_OR_COMMITTED_SITE,
second_shell_instance->process_reuse_policy());
EXPECT_NE(child->current_frame_host()->GetProcess(),
second_child->current_frame_host()->GetProcess());
}
class SitePerProcessWithMainFrameThresholdTest
: public SitePerProcessBrowserTest {
public:
static constexpr size_t kThreshold = 2;
SitePerProcessWithMainFrameThresholdTest() {
scoped_feature_list_.InitAndEnableFeatureWithParameters(
features::kProcessPerSiteUpToMainFrameThreshold,
{{"ProcessPerSiteMainFrameThreshold",
base::StringPrintf("%zu", kThreshold)}});
}
~SitePerProcessWithMainFrameThresholdTest() override = default;
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_P(SitePerProcessWithMainFrameThresholdTest,
ReuseProcessUpToThreshold) {
const GURL kUrl =
embedded_test_server()->GetURL("foo.test", "/page_with_iframe.html");
const GURL kOtherUrl =
embedded_test_server()->GetURL("bar.test", "/title1.html");
ASSERT_TRUE(NavigateToURL(shell(), kUrl));
RenderFrameHostImpl* main_frame_in_main_shell =
static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryMainFrame();
RenderFrameHostImpl* subframe_in_main_shell =
main_frame_in_main_shell->child_at(0)->current_frame_host();
ASSERT_EQ(main_frame_in_main_shell->GetProcess(),
subframe_in_main_shell->GetProcess());
std::vector<Shell*> shells;
for (size_t i = 0; i < kThreshold - 1; ++i) {
Shell* new_shell = CreateBrowser();
ASSERT_TRUE(NavigateToURL(new_shell, kOtherUrl));
ASSERT_TRUE(NavigateToURL(new_shell, kUrl));
RenderFrameHostImpl* new_frame =
static_cast<WebContentsImpl*>(new_shell->web_contents())
->GetPrimaryMainFrame();
if (main_frame_in_main_shell->GetSiteInstance()
->RequiresDedicatedProcess()) {
ASSERT_EQ(main_frame_in_main_shell->GetProcess(),
new_frame->GetProcess());
} else {
ASSERT_NE(main_frame_in_main_shell->GetProcess(),
new_frame->GetProcess());
}
shells.emplace_back(new_shell);
}
Shell* non_shared_shell = CreateBrowser();
ASSERT_TRUE(NavigateToURL(non_shared_shell, kOtherUrl));
ASSERT_TRUE(NavigateToURL(non_shared_shell, kUrl));
RenderFrameHostImpl* main_frame_in_non_shared_frame =
static_cast<WebContentsImpl*>(non_shared_shell->web_contents())
->GetPrimaryMainFrame();
ASSERT_NE(main_frame_in_main_shell->GetProcess(),
main_frame_in_non_shared_frame->GetProcess());
shells.emplace_back(non_shared_shell);
for (auto*& shell : shells) {
shell->Close();
}
}
IN_PROC_BROWSER_TEST_P(SitePerProcessWithMainFrameThresholdTest,
ReuseProcessOpenTabByCtrlClickLink) {
const GURL kUrl = embedded_test_server()->GetURL(
"foo.test", "/ctrl-click-subframe-link.html");
ASSERT_TRUE(NavigateToURL(shell(), kUrl));
RenderFrameHostImpl* main_frame =
static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryMainFrame();
ShellAddedObserver new_shell_observer;
ASSERT_TRUE(ExecJs(main_frame,
"window.domAutomationController.send(ctrlClickLink());"));
Shell* popup = new_shell_observer.GetShell();
ASSERT_EQ(main_frame->GetProcess(),
static_cast<WebContentsImpl*>(popup->web_contents())
->GetPrimaryMainFrame()
->GetProcess());
}
IN_PROC_BROWSER_TEST_P(SitePerProcessWithMainFrameThresholdTest,
ReuseProcessWithOpener) {
const GURL kUrl = embedded_test_server()->GetURL("foo.test", "/title1.html");
ASSERT_TRUE(NavigateToURL(shell(), kUrl));
RenderFrameHostImpl* main_frame =
static_cast<WebContentsImpl*>(shell()->web_contents())
->GetPrimaryMainFrame();
ShellAddedObserver new_shell_observer;
ASSERT_TRUE(
ExecJs(main_frame, "popup = window.open('/title1.html', '_blank');"));
Shell* popup = new_shell_observer.GetShell();
ASSERT_EQ(main_frame->GetProcess(),
static_cast<WebContentsImpl*>(popup->web_contents())
->GetPrimaryMainFrame()
->GetProcess());
}
INSTANTIATE_TEST_SUITE_P(All,
RequestDelayingSitePerProcessBrowserTest,
testing::ValuesIn(RenderDocumentFeatureLevelValues()));
#if BUILDFLAG(IS_ANDROID)
INSTANTIATE_TEST_SUITE_P(All,
SitePerProcessAndroidImeTest,
testing::ValuesIn(RenderDocumentFeatureLevelValues()));
#endif
INSTANTIATE_TEST_SUITE_P(All,
SitePerProcessAndProcessPerSiteBrowserTest,
testing::ValuesIn(RenderDocumentFeatureLevelValues()));
INSTANTIATE_TEST_SUITE_P(All,
SitePerProcessAutoplayBrowserTest,
testing::ValuesIn(RenderDocumentFeatureLevelValues()));
INSTANTIATE_TEST_SUITE_P(All,
SitePerProcessBrowserTest,
testing::ValuesIn(RenderDocumentFeatureLevelValues()));
INSTANTIATE_TEST_SUITE_P(All,
SitePerProcessBrowserTouchActionTest,
testing::ValuesIn(RenderDocumentFeatureLevelValues()));
INSTANTIATE_TEST_SUITE_P(All,
SitePerProcessIgnoreCertErrorsBrowserTest,
testing::ValuesIn(RenderDocumentFeatureLevelValues()));
INSTANTIATE_TEST_SUITE_P(All,
DisableProcessReusePolicyTest,
testing::ValuesIn(RenderDocumentFeatureLevelValues()));
INSTANTIATE_TEST_SUITE_P(All,
SitePerProcessWithMainFrameThresholdTest,
testing::ValuesIn(RenderDocumentFeatureLevelValues()));
#if BUILDFLAG(IS_ANDROID)
INSTANTIATE_TEST_SUITE_P(All,
TouchSelectionControllerClientAndroidSiteIsolationTest,
testing::ValuesIn(RenderDocumentFeatureLevelValues()));
#endif
INSTANTIATE_TEST_SUITE_P(All,
SitePerProcessBrowserTestWithLeakDetector,
testing::ValuesIn(RenderDocumentFeatureLevelValues()));
}