blob: 1ababe941833c6127e1150e5dcaba1fa4bc4af91 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_features.h"
#include "chrome/test/base/chrome_test_utils.h"
#include "chrome/test/base/platform_browser_test.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/site_isolation_policy.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_features.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_host_resolver.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/origin.h"
class JavascriptOptimizerBrowserTest : public PlatformBrowserTest {
public:
void SetUpOnMainThread() override {
PlatformBrowserTest::SetUpOnMainThread();
host_resolver()->AddRule("*", "127.0.0.1");
content::SetupCrossSiteRedirector(&embedded_https_test_server());
embedded_https_test_server().SetCertHostnames(
{"a.com", "*.a.com", "b.com", "*.b.com", "unrelated.com"});
ASSERT_TRUE(embedded_https_test_server().Start());
}
content::WebContents* web_contents() {
return chrome_test_utils::GetActiveWebContents(this);
}
bool AreV8OptimizationsDisabledOnActiveWebContents() {
return web_contents()
->GetPrimaryMainFrame()
->GetProcess()
->AreV8OptimizationsDisabled();
}
};
class JavascriptOptimizerBrowserTest_NoOriginKeyedProcessesByDefault
: public JavascriptOptimizerBrowserTest {
public:
JavascriptOptimizerBrowserTest_NoOriginKeyedProcessesByDefault() {
feature_list_.InitAndDisableFeature(
features::kOriginKeyedProcessesByDefault);
}
private:
base::test::ScopedFeatureList feature_list_;
};
class JavascriptOptimizerBrowserTest_OriginKeyedProcessesByDefault
: public JavascriptOptimizerBrowserTest {
public:
JavascriptOptimizerBrowserTest_OriginKeyedProcessesByDefault() {
feature_list_.InitWithFeatures(
{features::kOriginKeyedProcessesByDefault, features::kSitePerProcess},
{});
}
private:
base::test::ScopedFeatureList feature_list_;
};
// Test that V8 optimization is disabled when the user disables v8 optimization
// by default via chrome://settings.
IN_PROC_BROWSER_TEST_F(JavascriptOptimizerBrowserTest,
V8SiteSettingDefaultOff) {
auto* map = HostContentSettingsMapFactory::GetForProfile(
chrome_test_utils::GetProfile(this));
map->SetDefaultContentSetting(ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_BLOCK);
ASSERT_TRUE(content::NavigateToURL(
web_contents(), embedded_https_test_server().GetURL("/simple.html")));
EXPECT_TRUE(AreV8OptimizationsDisabledOnActiveWebContents());
}
// Test that V8 optimization is disabled when the user disables v8 optimization
// via chrome://settings for a specific site.
IN_PROC_BROWSER_TEST_F(JavascriptOptimizerBrowserTest,
DisabledViaSiteSpecificSetting) {
auto* map = HostContentSettingsMapFactory::GetForProfile(
chrome_test_utils::GetProfile(this));
map->SetDefaultContentSetting(ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_ALLOW);
map->SetContentSettingCustomScope(
ContentSettingsPattern::FromString("https://a.com:*"),
ContentSettingsPattern::FromString("*"),
ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_BLOCK);
ASSERT_TRUE(content::NavigateToURL(
web_contents(),
embedded_https_test_server().GetURL("a.com", "/simple.html")));
EXPECT_TRUE(AreV8OptimizationsDisabledOnActiveWebContents());
}
// Test when an origin that matches an exception is loaded in a subframe, the
// origin is not isolated and the exception is not applied. This test does not
// apply if OriginKeyedProcessesByDefault is enabled because in that mode all
// origins would already be isolated on first navigation.
IN_PROC_BROWSER_TEST_F(
JavascriptOptimizerBrowserTest_NoOriginKeyedProcessesByDefault,
ExceptionOriginLoadedInSubframeIsNotIsolatedOnFirstNavigation) {
auto* policy = content::ChildProcessSecurityPolicy::GetInstance();
auto* map = HostContentSettingsMapFactory::GetForProfile(
chrome_test_utils::GetProfile(this));
map->SetDefaultContentSetting(ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_ALLOW);
map->SetContentSettingCustomScope(
ContentSettingsPattern::FromString("https://b.com:*"),
ContentSettingsPattern::FromString("*"),
ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_BLOCK);
// Request a.com, which loads b.com in an iframe.
ASSERT_TRUE(content::NavigateToURL(
web_contents(),
embedded_https_test_server().GetURL("a.com", "/iframe_cross_site.html")));
content::RenderFrameHost* child_frame =
content::ChildFrameAt(web_contents()->GetPrimaryMainFrame(), 0);
// b.com will be marked for isolation when loaded in a subframe. But the
// exception won't be followed until it is loaded in a future browsing
// context.
EXPECT_TRUE(child_frame->GetLastCommittedOrigin().DomainIs("b.com"));
EXPECT_TRUE(policy->IsIsolatedSiteFromSource(
url::Origin::Create(GURL("https://b.com/")),
content::ChildProcessSecurityPolicy::IsolatedOriginSource::
USER_TRIGGERED));
if (content::SiteIsolationPolicy::UseDedicatedProcessesForAllSites()) {
// If dedicated processes are used for all sites, then b.com's rules will be
// followed so this case doesn't apply. So in these cases, we are verifying
// that new exceptions are respected in sub-frames.
EXPECT_TRUE(child_frame->GetProcess()->AreV8OptimizationsDisabled());
EXPECT_TRUE(child_frame->GetSiteInstance()->RequiresDedicatedProcess());
} else {
EXPECT_FALSE(child_frame->GetProcess()->AreV8OptimizationsDisabled());
EXPECT_FALSE(child_frame->GetSiteInstance()->RequiresDedicatedProcess());
}
// Confirm that the exception applies when b.com is loaded in a new
// BrowsingInstance. (This is because NavigateToURL performs a
// browser-initiated navigation which will swap BrowsingInstances when
// navigating cross-site.)
ASSERT_TRUE(content::NavigateToURL(
web_contents(),
embedded_https_test_server().GetURL("b.com", "/title1.html")));
EXPECT_TRUE(AreV8OptimizationsDisabledOnActiveWebContents());
EXPECT_TRUE(web_contents()
->GetPrimaryMainFrame()
->GetSiteInstance()
->RequiresDedicatedProcess());
EXPECT_TRUE(web_contents()
->GetPrimaryMainFrame()
->GetProcess()
->IsProcessLockedToSiteForTesting());
}
// Test that when an origin that matches an exception is loaded in a main frame
// first, then if the origin is loaded in a subframe later, the origin will be
// isolated and the exception will be applied in both cases.
IN_PROC_BROWSER_TEST_F(
JavascriptOptimizerBrowserTest_NoOriginKeyedProcessesByDefault,
ExceptionOriginLoadedFirstWillBeIsolatedInSubframe) {
auto* policy = content::ChildProcessSecurityPolicy::GetInstance();
auto* map = HostContentSettingsMapFactory::GetForProfile(
chrome_test_utils::GetProfile(this));
map->SetDefaultContentSetting(ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_ALLOW);
map->SetContentSettingCustomScope(
ContentSettingsPattern::FromString("https://b.com:*"),
ContentSettingsPattern::FromString("*"),
ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_BLOCK);
// Navigate to b.com directly.
ASSERT_TRUE(content::NavigateToURL(
web_contents(),
embedded_https_test_server().GetURL("b.com", "/title1.html")));
EXPECT_TRUE(AreV8OptimizationsDisabledOnActiveWebContents());
EXPECT_TRUE(web_contents()
->GetPrimaryMainFrame()
->GetSiteInstance()
->RequiresDedicatedProcess());
EXPECT_TRUE(web_contents()
->GetPrimaryMainFrame()
->GetProcess()
->IsProcessLockedToSiteForTesting());
// Then navigate to a.com that embeds b.com in an iframe.
ASSERT_TRUE(content::NavigateToURL(
web_contents(),
embedded_https_test_server().GetURL("a.com", "/iframe_cross_site.html")));
content::RenderFrameHost* child_frame =
content::ChildFrameAt(web_contents()->GetPrimaryMainFrame(), 0);
// Since b.com is already marked for isolation, when loaded as a subframe, the
// subframe will still have the isolation (and the js-opt setting) applied.
EXPECT_FALSE(AreV8OptimizationsDisabledOnActiveWebContents());
EXPECT_TRUE(child_frame->GetLastCommittedOrigin().DomainIs("b.com"));
EXPECT_TRUE(policy->IsIsolatedSiteFromSource(
url::Origin::Create(GURL("https://b.com/")),
content::ChildProcessSecurityPolicy::IsolatedOriginSource::
USER_TRIGGERED));
EXPECT_TRUE(child_frame->GetProcess()->AreV8OptimizationsDisabled());
EXPECT_TRUE(child_frame->GetSiteInstance()->RequiresDedicatedProcess());
EXPECT_TRUE(child_frame->GetProcess()->IsProcessLockedToSiteForTesting());
}
// Test that when a rule is removed during a session, then the origin will still
// be isolated but the updated js-opt setting will be applied. This test does
// not apply under OriginKeyedProcessesByDefault because all origins would be
// isolated.
IN_PROC_BROWSER_TEST_F(
JavascriptOptimizerBrowserTest_NoOriginKeyedProcessesByDefault,
RemoveRuleOriginIsStillIsolatedButIsAllowed) {
auto* policy = content::ChildProcessSecurityPolicy::GetInstance();
auto* map = HostContentSettingsMapFactory::GetForProfile(
chrome_test_utils::GetProfile(this));
map->SetDefaultContentSetting(ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_ALLOW);
map->SetContentSettingCustomScope(
ContentSettingsPattern::FromString("https://a.com:*"),
ContentSettingsPattern::FromString("*"),
ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_BLOCK);
// Before any navigation, a site with an exception is not isolated.
EXPECT_FALSE(policy->IsIsolatedSiteFromSource(
url::Origin::Create(GURL("https://a.com/")),
content::ChildProcessSecurityPolicy::IsolatedOriginSource::
USER_TRIGGERED));
ASSERT_TRUE(content::NavigateToURL(
web_contents(),
embedded_https_test_server().GetURL("a.com", "/simple.html")));
// After navigation, the site will be isolated.
EXPECT_TRUE(policy->IsIsolatedSiteFromSource(
url::Origin::Create(GURL("https://a.com/")),
content::ChildProcessSecurityPolicy::IsolatedOriginSource::
USER_TRIGGERED));
EXPECT_TRUE(AreV8OptimizationsDisabledOnActiveWebContents());
EXPECT_TRUE(web_contents()->GetSiteInstance()->RequiresDedicatedProcess());
EXPECT_TRUE(web_contents()
->GetPrimaryMainFrame()
->GetProcess()
->IsProcessLockedToSiteForTesting());
// Delete the custom setting
map->SetContentSettingCustomScope(
ContentSettingsPattern::FromString("https://a.com:*"),
ContentSettingsPattern::FromString("*"),
ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_DEFAULT);
// Navigate to different origin so that the subsequent navigation to a.com
// occurs in a different BrowsingInstanceId.
ASSERT_TRUE(content::NavigateToURL(
web_contents(),
embedded_https_test_server().GetURL("unrelated.com", "/simple.html")));
ASSERT_TRUE(content::NavigateToURL(
web_contents(),
embedded_https_test_server().GetURL("a.com", "/simple.html")));
// Despite the settings change, the new a.com document should still be
// isolated because policy changes that result in no longer isolating an
// origin only take effect after restart.
EXPECT_TRUE(policy->IsIsolatedSiteFromSource(
url::Origin::Create(GURL("https://a.com/")),
content::ChildProcessSecurityPolicy::IsolatedOriginSource::
USER_TRIGGERED));
EXPECT_TRUE(web_contents()->GetSiteInstance()->RequiresDedicatedProcess());
EXPECT_TRUE(web_contents()
->GetPrimaryMainFrame()
->GetProcess()
->IsProcessLockedToSiteForTesting());
// Additionally, since a.com no longer has a specific policy, the loaded
// document should follow the default setting (allow optimizations).
EXPECT_FALSE(AreV8OptimizationsDisabledOnActiveWebContents());
}
// Test that when an exception exists for a.com, navigation to sub.a.com will
// also have the setting applied.
IN_PROC_BROWSER_TEST_F(
JavascriptOptimizerBrowserTest_NoOriginKeyedProcessesByDefault,
ExceptionForSiteAppliesToSubSite) {
auto* map = HostContentSettingsMapFactory::GetForProfile(
chrome_test_utils::GetProfile(this));
map->SetDefaultContentSetting(ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_ALLOW);
map->SetContentSettingCustomScope(
ContentSettingsPattern::FromString("https://a.com:*"),
ContentSettingsPattern::FromString("*"),
ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_BLOCK);
ASSERT_TRUE(content::NavigateToURL(
web_contents(),
embedded_https_test_server().GetURL("a.com", "/simple.html")));
EXPECT_TRUE(AreV8OptimizationsDisabledOnActiveWebContents());
ASSERT_TRUE(content::NavigateToURL(
web_contents(),
embedded_https_test_server().GetURL("sub.a.com", "/simple.html")));
// True under site isolation.
EXPECT_TRUE(AreV8OptimizationsDisabledOnActiveWebContents());
}
// Under origin isolation, test that when an exception exists for a.com,
// navigation to sub.a.com will not have the setting applied. This is because
// the origin is passed in to AreV8OptimizationsDisabledForSite() when
// evaluating the rule.
IN_PROC_BROWSER_TEST_F(
JavascriptOptimizerBrowserTest_OriginKeyedProcessesByDefault,
ExceptionForSiteDoesNotApplyToSubSite) {
if (!content::SiteIsolationPolicy::
AreOriginKeyedProcessesEnabledByDefault()) {
GTEST_SKIP()
<< "skipping: OriginKeyedProcessesEnabledByDefault needs to be true";
}
auto* map = HostContentSettingsMapFactory::GetForProfile(
chrome_test_utils::GetProfile(this));
map->SetDefaultContentSetting(ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_ALLOW);
map->SetContentSettingCustomScope(
ContentSettingsPattern::FromString("https://a.com:*"),
ContentSettingsPattern::FromString("*"),
ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_BLOCK);
ASSERT_TRUE(content::NavigateToURL(
web_contents(),
embedded_https_test_server().GetURL("a.com", "/simple.html")));
EXPECT_TRUE(AreV8OptimizationsDisabledOnActiveWebContents());
ASSERT_TRUE(content::NavigateToURL(
web_contents(),
embedded_https_test_server().GetURL("sub.a.com", "/simple.html")));
// False under origin isolation because the origin won't match the content
// setting for a.com.
EXPECT_FALSE(AreV8OptimizationsDisabledOnActiveWebContents());
}
// Test that if there's a rule for a.com that differs from the default, then the
// user can't specify a rule for sub.a.com that contradicts that rule.
// TODO(crbug.com/413695645): Make it possible for users to specify overrides so
// that sub.a.com's behavior can differ from a.com's behavior.
IN_PROC_BROWSER_TEST_F(JavascriptOptimizerBrowserTest,
ExceptionForSiteAppliesToSubSiteButCannotBeOverridden) {
auto* policy = content::ChildProcessSecurityPolicy::GetInstance();
auto* map = HostContentSettingsMapFactory::GetForProfile(
chrome_test_utils::GetProfile(this));
map->SetDefaultContentSetting(ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_ALLOW);
map->SetContentSettingCustomScope(
ContentSettingsPattern::FromString("https://sub.a.com:*"),
ContentSettingsPattern::FromString("*"),
ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_ALLOW);
map->SetContentSettingCustomScope(
ContentSettingsPattern::FromString("https://a.com:*"),
ContentSettingsPattern::FromString("*"),
ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_BLOCK);
// Since this exception matches the default, it will not be isolated.
ASSERT_TRUE(content::NavigateToURL(
web_contents(),
embedded_https_test_server().GetURL("sub.a.com", "/simple.html")));
EXPECT_FALSE(policy->IsIsolatedSiteFromSource(
url::Origin::Create(GURL("https://a.com/")),
content::ChildProcessSecurityPolicy::IsolatedOriginSource::
USER_TRIGGERED));
if (content::AreStrictSiteInstancesEnabled() &&
!content::SiteIsolationPolicy::
AreOriginKeyedProcessesEnabledByDefault()) {
// if a.com is isolated already (as is the case with full site isolation)
// or if DefaultSiteInstanceGroups are enabled, and origin isolation is not
// used, the navigation to sub.a.com will be made in a SiteInstance with a
// "a.com" site URL, which will match a.com BLOCK rule.
EXPECT_TRUE(AreV8OptimizationsDisabledOnActiveWebContents());
} else {
// If nothing is isolated by default (like on Android), we'll navigate in a
// default SiteInstance which won't match that rule and will instead
// retrieve the default rule. TODO(crbug.com/413695645): make it possible
// for users to specify overrides so that sub.a.com's behavior can differ
// from a.com's behavior.
EXPECT_FALSE(AreV8OptimizationsDisabledOnActiveWebContents());
}
ASSERT_TRUE(content::NavigateToURL(
web_contents(),
embedded_https_test_server().GetURL("a.com", "/simple.html")));
EXPECT_TRUE(AreV8OptimizationsDisabledOnActiveWebContents());
// Navigate back to sub.a.com, and we would like for js-opt to be enabled, but
// they are disabled instead, because url provided to
// AreV8OptimizationsDisabledForSite is a.com, which matches the block rule.
// Ideally we'd be able to specify rules here, but to do that we need to pass
// in the origin instead of the site. Currently, the site is passed because
// sub.a.com is not origin isolated. TODO(crbug.com/413695645): Make it
// possible for users to specify overrides so that sub.a.com's behavior can
// differ from a.com's behavior.
ASSERT_TRUE(content::NavigateToURL(
web_contents(),
embedded_https_test_server().GetURL("sub.a.com", "/simple.html")));
if (content::SiteIsolationPolicy::AreOriginKeyedProcessesEnabledByDefault()) {
// Under origin isolation, the rule won't match sub.a.com, so optimizers
// remain enabled.
EXPECT_FALSE(AreV8OptimizationsDisabledOnActiveWebContents());
} else {
// Under site isolation, sub.a.com will be evaluated as a.com so the rule
// will match.
EXPECT_TRUE(AreV8OptimizationsDisabledOnActiveWebContents());
}
}
// Test that a rule can be specified for sub.a.com. and a.com can have different
// behavior.
IN_PROC_BROWSER_TEST_F(
JavascriptOptimizerBrowserTest,
RuleForSubSiteCanBeSpecifiedAndSiteCanStillFollowDefaultRule) {
#if BUILDFLAG(IS_LINUX)
// TODO(421325694): This test fails on linux when bfcache is disabled.
if (!base::FeatureList::IsEnabled(features::kBackForwardCache)) {
GTEST_SKIP();
}
#endif
auto* policy = content::ChildProcessSecurityPolicy::GetInstance();
auto* map = HostContentSettingsMapFactory::GetForProfile(
chrome_test_utils::GetProfile(this));
map->SetDefaultContentSetting(ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_ALLOW);
map->SetContentSettingCustomScope(
ContentSettingsPattern::FromString("https://sub.a.com:*"),
ContentSettingsPattern::FromString("*"),
ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_BLOCK);
map->SetContentSettingCustomScope(
ContentSettingsPattern::FromString("https://a.com:*"),
ContentSettingsPattern::FromString("*"),
ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_ALLOW);
ASSERT_TRUE(content::NavigateToURL(
web_contents(),
embedded_https_test_server().GetURL("a.com", "/simple.html")));
EXPECT_FALSE(policy->IsIsolatedSiteFromSource(
url::Origin::Create(GURL("https://a.com/")),
content::ChildProcessSecurityPolicy::IsolatedOriginSource::
USER_TRIGGERED));
EXPECT_FALSE(AreV8OptimizationsDisabledOnActiveWebContents());
// In this case, since a.com's policy matched the default, a.com is not
// isolated, but sub.a.com will be isolated so sub.a.com follows its
// exception.
ASSERT_TRUE(content::NavigateToURL(
web_contents(),
embedded_https_test_server().GetURL("sub.a.com", "/simple.html")));
EXPECT_TRUE(AreV8OptimizationsDisabledOnActiveWebContents());
// If we now navigate back to a.com, just like before, the a.com will still
// not be isolated, and optimizers will be allowed.
ASSERT_TRUE(content::NavigateToURL(
web_contents(),
embedded_https_test_server().GetURL("a.com", "/simple.html")));
EXPECT_FALSE(policy->IsIsolatedSiteFromSource(
url::Origin::Create(GURL("https://a.com/")),
content::ChildProcessSecurityPolicy::IsolatedOriginSource::
USER_TRIGGERED));
EXPECT_FALSE(AreV8OptimizationsDisabledOnActiveWebContents());
}
// Test that exceptions which match the main frame are not propagated down to
// subframes from different sites. Additionally, if the subframe is later
// navigated to a site that matches the main frame, the main frame's exception
// will apply.
IN_PROC_BROWSER_TEST_F(
JavascriptOptimizerBrowserTest_NoOriginKeyedProcessesByDefault,
ExceptionForTopFrameDoesNotApplyToSubFrame) {
auto* map = HostContentSettingsMapFactory::GetForProfile(
chrome_test_utils::GetProfile(this));
map->SetDefaultContentSetting(ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_ALLOW);
map->SetContentSettingCustomScope(
ContentSettingsPattern::FromString("https://a.com:*"),
ContentSettingsPattern::FromString("*"),
ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_BLOCK);
// Navigate to a.com which embeds b.com.
ASSERT_TRUE(content::NavigateToURL(
web_contents(),
embedded_https_test_server().GetURL("a.com", "/iframe_cross_site.html")));
// The top-level frame should have optimizations disabled.
EXPECT_TRUE(AreV8OptimizationsDisabledOnActiveWebContents());
// But the frame for b.com follows the default policy.
content::RenderFrameHost* child_frame =
content::ChildFrameAt(web_contents()->GetPrimaryMainFrame(), 0);
EXPECT_FALSE(child_frame->GetProcess()->AreV8OptimizationsDisabled());
EXPECT_TRUE(child_frame->GetLastCommittedOrigin().DomainIs("b.com"));
// Now, navigate the child_frame to sub.a.com and confirm that a.com's disable
// setting applies to sub.a.com.
ASSERT_TRUE(content::NavigateIframeToURL(
web_contents(), "frame1",
embedded_https_test_server().GetURL("sub.a.com", "/simple.html")));
child_frame = content::ChildFrameAt(web_contents()->GetPrimaryMainFrame(), 0);
EXPECT_EQ(child_frame->GetLastCommittedURL().host(), "sub.a.com");
// True under site isolation but not origin isolation.
EXPECT_TRUE(child_frame->GetProcess()->AreV8OptimizationsDisabled());
}
// Test that sites isolated due to JavaScript optimization setting will not be
// put into processes for other sites when over the limit. This should already
// be covered by other IsolatedOriginTests, but this case ensures that
// JavaScript optimization is handled correctly.
IN_PROC_BROWSER_TEST_F(JavascriptOptimizerBrowserTest, ProcessLimitWorks) {
content::RenderProcessHost::SetMaxRendererProcessCount(1);
auto* map = HostContentSettingsMapFactory::GetForProfile(
chrome_test_utils::GetProfile(this));
map->SetDefaultContentSetting(ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_ALLOW);
map->SetContentSettingCustomScope(
ContentSettingsPattern::FromString("https://b.com:*"),
ContentSettingsPattern::FromString("*"),
ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_BLOCK);
// Navigate to b.com first to ensure it is on the isolated origins list.
ASSERT_TRUE(content::NavigateToURL(
web_contents(),
embedded_https_test_server().GetURL("b.com", "/simple.html")));
// Visit a.com in a new BrowsingInstance, which iframes b.com and c.com.
ASSERT_TRUE(content::NavigateToURL(
web_contents(),
embedded_https_test_server().GetURL("a.com", "/iframe_cross_site.html")));
content::RenderFrameHost* a_com_frame = web_contents()->GetPrimaryMainFrame();
content::RenderFrameHost* b_com_frame = content::ChildFrameAt(a_com_frame, 0);
content::RenderFrameHost* c_com_frame = content::ChildFrameAt(a_com_frame, 1);
if (content::SiteIsolationPolicy::UseDedicatedProcessesForAllSites()) {
// When all sites are isolated, each frame should be in its own process.
EXPECT_NE(a_com_frame->GetProcess(), b_com_frame->GetProcess());
EXPECT_NE(c_com_frame->GetProcess(), b_com_frame->GetProcess());
EXPECT_NE(a_com_frame->GetProcess(), c_com_frame->GetProcess());
} else {
// When partial site isolation is enabled, the result is that b.com should
// be put into its own process despite Chrome being at the soft process
// limit. a.com and c.com will end up together.
EXPECT_NE(a_com_frame->GetProcess(), b_com_frame->GetProcess());
EXPECT_NE(c_com_frame->GetProcess(), b_com_frame->GetProcess());
EXPECT_EQ(a_com_frame->GetProcess(), c_com_frame->GetProcess());
}
}
namespace {
void NavigateChangeV8OptPriorToWindowOpen(content::WebContents* web_contents,
const GURL& navigate_url,
const GURL& window_open_url) {
Profile* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
auto* map = HostContentSettingsMapFactory::GetForProfile(profile);
map->SetDefaultContentSetting(ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_ALLOW);
ASSERT_TRUE(content::NavigateToURL(web_contents, navigate_url));
// Simulate changing the default v8-optimization preference via
// chrome://settings in a different tab.
map->SetDefaultContentSetting(ContentSettingsType::JAVASCRIPT_OPTIMIZER,
ContentSetting::CONTENT_SETTING_BLOCK);
content::TestNavigationObserver popup_observer(nullptr);
popup_observer.StartWatchingNewWebContents();
content::EvalJsResult result =
content::EvalJs(web_contents->GetPrimaryMainFrame(),
"window.open(\"" + window_open_url.spec() + "\");");
popup_observer.Wait();
}
} // anonymous namespace
// Test that a same-origin window.open() call uses the same process regardless
// of whether the user changed the v8-optimization state.
IN_PROC_BROWSER_TEST_F(
JavascriptOptimizerBrowserTest,
ChangeJavascriptOptimizerStatePriorToSameOriginWindowOpen) {
GURL url = embedded_https_test_server().GetURL("a.com", "/simple.html");
NavigateChangeV8OptPriorToWindowOpen(web_contents(), url, url);
std::vector<content::WebContents*> all_web_contents =
content::GetAllWebContents();
ASSERT_EQ(2u, all_web_contents.size());
content::RenderFrameHost* frame0 = all_web_contents[0]->GetPrimaryMainFrame();
content::RenderFrameHost* frame1 = all_web_contents[1]->GetPrimaryMainFrame();
EXPECT_EQ(frame0->GetProcess(), frame1->GetProcess());
EXPECT_EQ(frame0->GetSiteInstance(), frame1->GetSiteInstance());
}
// Test that when the features::kOriginKeyedProcessesByDefault feature is
// disabled that a same-site window.open() call uses the same process regardless
// of whether the user changed the v8-optimization state.
IN_PROC_BROWSER_TEST_F(
JavascriptOptimizerBrowserTest_NoOriginKeyedProcessesByDefault,
ChangeJavascriptOptimizerStatePriorToSameSiteWindowOpen) {
GURL url = embedded_https_test_server().GetURL("a.com", "/simple.html");
GURL same_site_url =
embedded_https_test_server().GetURL("foo.a.com", "/simple.html");
NavigateChangeV8OptPriorToWindowOpen(web_contents(), url, same_site_url);
std::vector<content::WebContents*> all_web_contents =
content::GetAllWebContents();
ASSERT_EQ(2u, all_web_contents.size());
content::RenderFrameHost* frame0 = all_web_contents[0]->GetPrimaryMainFrame();
content::RenderFrameHost* frame1 = all_web_contents[1]->GetPrimaryMainFrame();
EXPECT_EQ(frame0->GetProcess(), frame1->GetProcess());
EXPECT_EQ(frame0->GetSiteInstance(), frame1->GetSiteInstance());
}