| // Copyright 2019 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/command_line.h" |
| #include "base/strings/escape.h" |
| #include "base/test/bind.h" |
| #include "base/test/gtest_util.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "build/build_config.h" |
| #include "content/browser/renderer_host/navigation_request.h" |
| #include "content/browser/renderer_host/render_frame_host_impl.h" |
| #include "content/browser/renderer_host/render_process_host_impl.h" |
| #include "content/browser/web_contents/web_contents_impl.h" |
| #include "content/common/content_navigation_policy.h" |
| #include "content/public/browser/site_isolation_policy.h" |
| #include "content/public/common/content_features.h" |
| #include "content/public/common/url_constants.h" |
| #include "content/public/test/browser_test.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "content/public/test/content_browser_test.h" |
| #include "content/public/test/content_browser_test_utils.h" |
| #include "content/public/test/content_mock_cert_verifier.h" |
| #include "content/public/test/test_navigation_observer.h" |
| #include "content/public/test/url_loader_interceptor.h" |
| #include "content/shell/browser/shell.h" |
| #include "content/test/content_browser_test_utils_internal.h" |
| #include "content/test/render_document_feature.h" |
| #include "net/dns/mock_host_resolver.h" |
| #include "net/test/embedded_test_server/default_handlers.h" |
| #include "net/test/embedded_test_server/http_request.h" |
| #include "net/test/embedded_test_server/http_response.h" |
| #include "net/test/embedded_test_server/request_handler_util.h" |
| #include "services/network/public/cpp/cross_origin_embedder_policy.h" |
| #include "services/network/public/cpp/cross_origin_opener_policy.h" |
| #include "services/network/public/cpp/features.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| |
| using ::testing::HasSubstr; |
| |
| namespace content { |
| |
| namespace { |
| |
| network::CrossOriginOpenerPolicy CoopSameOrigin() { |
| network::CrossOriginOpenerPolicy coop; |
| coop.value = network::mojom::CrossOriginOpenerPolicyValue::kSameOrigin; |
| coop.soap_by_default_value = |
| network::mojom::CrossOriginOpenerPolicyValue::kSameOrigin; |
| return coop; |
| } |
| |
| network::CrossOriginOpenerPolicy CoopSameOriginPlusCoep() { |
| network::CrossOriginOpenerPolicy coop; |
| coop.value = |
| network::mojom::CrossOriginOpenerPolicyValue::kSameOriginPlusCoep; |
| coop.soap_by_default_value = |
| network::mojom::CrossOriginOpenerPolicyValue::kSameOriginPlusCoep; |
| return coop; |
| } |
| |
| network::CrossOriginOpenerPolicy CoopSameOriginAllowPopups() { |
| network::CrossOriginOpenerPolicy coop; |
| coop.value = |
| network::mojom::CrossOriginOpenerPolicyValue::kSameOriginAllowPopups; |
| coop.soap_by_default_value = |
| network::mojom::CrossOriginOpenerPolicyValue::kSameOriginAllowPopups; |
| return coop; |
| } |
| |
| network::CrossOriginOpenerPolicy CoopSameOriginAllowPopupsPlusCoep() { |
| network::CrossOriginOpenerPolicy coop; |
| coop.value = network::mojom::CrossOriginOpenerPolicyValue:: |
| kSameOriginAllowPopupsPlusCoep; |
| coop.soap_by_default_value = network::mojom::CrossOriginOpenerPolicyValue:: |
| kSameOriginAllowPopupsPlusCoep; |
| return coop; |
| } |
| |
| // This is the value of COOP when navigating to a page without COOP set: |
| // - value is kUnsafeNone |
| // - soap_by_default_value is kSameOriginAllowPopups |
| network::CrossOriginOpenerPolicy CoopUnsafeNoneWithSoapByDefault() { |
| network::CrossOriginOpenerPolicy coop; |
| coop.soap_by_default_value = |
| network::mojom::CrossOriginOpenerPolicyValue::kSameOriginAllowPopups; |
| return coop; |
| } |
| |
| network::CrossOriginOpenerPolicy CoopUnsafeNone() { |
| network::CrossOriginOpenerPolicy coop; |
| // Using the default value. |
| return coop; |
| } |
| |
| std::unique_ptr<net::test_server::HttpResponse> |
| CrossOriginIsolatedCrossOriginRedirectHandler( |
| const net::test_server::HttpRequest& request) { |
| GURL request_url = request.GetURL(); |
| std::string dest = |
| base::UnescapeBinaryURLComponent(request_url.query_piece()); |
| net::test_server::RequestQuery query = |
| net::test_server::ParseQuery(request_url); |
| |
| auto http_response = std::make_unique<net::test_server::BasicHttpResponse>(); |
| http_response->set_code(net::HttpStatusCode::HTTP_FOUND); |
| http_response->AddCustomHeader("Location", dest); |
| http_response->AddCustomHeader("Cross-Origin-Opener-Policy", "same-origin"); |
| http_response->AddCustomHeader("Cross-Origin-Embedder-Policy", |
| "require-corp"); |
| return http_response; |
| } |
| |
| class CrossOriginOpenerPolicyBrowserTest |
| : public ContentBrowserTest, |
| public ::testing::WithParamInterface<std::tuple<std::string, bool>> { |
| public: |
| CrossOriginOpenerPolicyBrowserTest() |
| : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) { |
| // Enable COOP/COEP: |
| feature_list_.InitAndEnableFeature( |
| network::features::kCrossOriginOpenerPolicy); |
| |
| // Enable RenderDocument: |
| InitAndEnableRenderDocumentFeature(&feature_list_for_render_document_, |
| std::get<0>(GetParam())); |
| // Enable BackForwardCache: |
| if (IsBackForwardCacheEnabled()) { |
| feature_list_for_back_forward_cache_.InitWithFeaturesAndParameters( |
| {{features::kBackForwardCache, |
| {{"TimeToLiveInBackForwardCacheInSeconds", "3600"}}}}, |
| // Allow BackForwardCache for all devices regardless of their memory. |
| {features::kBackForwardCacheMemoryControls}); |
| } else { |
| feature_list_for_back_forward_cache_.InitWithFeatures( |
| {}, {features::kBackForwardCache}); |
| } |
| } |
| |
| // Provides meaningful param names instead of /0, /1, ... |
| static std::string DescribeParams( |
| const testing::TestParamInfo<ParamType>& info) { |
| auto [render_document_level, enable_back_forward_cache] = info.param; |
| return base::StringPrintf( |
| "%s_%s", |
| GetRenderDocumentLevelNameForTestParams(render_document_level).c_str(), |
| enable_back_forward_cache ? "BFCacheEnabled" : "BFCacheDisabled"); |
| } |
| |
| bool IsBackForwardCacheEnabled() { return std::get<1>(GetParam()); } |
| |
| net::EmbeddedTestServer* https_server() { return &https_server_; } |
| |
| protected: |
| WebContentsImpl* web_contents() const { |
| return static_cast<WebContentsImpl*>(shell()->web_contents()); |
| } |
| |
| RenderFrameHostImpl* current_frame_host() { |
| return web_contents()->GetMainFrame(); |
| } |
| |
| void SetUpOnMainThread() override { |
| ContentBrowserTest::SetUpOnMainThread(); |
| mock_cert_verifier_.mock_cert_verifier()->set_default_result(net::OK); |
| |
| host_resolver()->AddRule("*", "127.0.0.1"); |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| https_server()->ServeFilesFromSourceDirectory(GetTestDataFilePath()); |
| SetupCrossSiteRedirector(https_server()); |
| net::test_server::RegisterDefaultHandlers(&https_server_); |
| https_server_.RegisterDefaultHandler(base::BindRepeating( |
| &net::test_server::HandlePrefixedRequest, |
| "/redirect-with-coop-coep-headers", |
| base::BindRepeating(CrossOriginIsolatedCrossOriginRedirectHandler))); |
| |
| ASSERT_TRUE(https_server()->Start()); |
| } |
| |
| private: |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| ContentBrowserTest::SetUpCommandLine(command_line); |
| mock_cert_verifier_.SetUpCommandLine(command_line); |
| } |
| |
| void SetUpInProcessBrowserTestFixture() override { |
| ContentBrowserTest::SetUpInProcessBrowserTestFixture(); |
| mock_cert_verifier_.SetUpInProcessBrowserTestFixture(); |
| } |
| |
| void TearDownInProcessBrowserTestFixture() override { |
| ContentBrowserTest::TearDownInProcessBrowserTestFixture(); |
| mock_cert_verifier_.TearDownInProcessBrowserTestFixture(); |
| } |
| |
| content::ContentMockCertVerifier mock_cert_verifier_; |
| base::test::ScopedFeatureList feature_list_; |
| base::test::ScopedFeatureList feature_list_for_render_document_; |
| base::test::ScopedFeatureList feature_list_for_back_forward_cache_; |
| net::EmbeddedTestServer https_server_; |
| }; |
| |
| // Same as CrossOriginOpenerPolicyBrowserTest, but disable SharedArrayBuffer by |
| // default for non crossOriginIsolated process. This is the state we will reach |
| // after resolving: https://crbug.com/1144104 |
| class NoSharedArrayBufferByDefault : public CrossOriginOpenerPolicyBrowserTest { |
| public: |
| NoSharedArrayBufferByDefault() { |
| // Disable SharedArrayBuffer in non crossOriginIsolated process. |
| feature_list_.InitWithFeatures( |
| // Enabled: |
| {}, |
| // Disabled: |
| { |
| features::kSharedArrayBuffer, |
| }); |
| } |
| |
| private: |
| base::test::ScopedFeatureList feature_list_; |
| }; |
| |
| // Same as CrossOriginOpenerPolicyBrowserTest, but enable COOP:SOAPPC. |
| // See https://crbug.com/1221127. |
| class SameOriginAllowPopupsPlusCoepBrowserTest |
| : public CrossOriginOpenerPolicyBrowserTest { |
| public: |
| SameOriginAllowPopupsPlusCoepBrowserTest() { |
| feature_list_.InitWithFeatures( |
| {network::features::kCoopSameOriginAllowPopupsPlusCoep}, {}); |
| } |
| |
| private: |
| base::test::ScopedFeatureList feature_list_; |
| }; |
| |
| // Certain features are only active when SiteIsolation is off or restricted. |
| // This is the case for example for Default SiteInstances that are used on |
| // Android to limit the number of processes. Testing these particularities of |
| // the process model and their interaction with cross-origin isolation requires |
| // to disable SiteIsolation. |
| class NoSiteIsolationCrossOriginIsolationBrowserTest |
| : public CrossOriginOpenerPolicyBrowserTest { |
| public: |
| NoSiteIsolationCrossOriginIsolationBrowserTest() { |
| // Disable the heuristic to isolate COOP pages from the default |
| // SiteInstance. This is otherwise on by default on Android. |
| feature_list_.InitWithFeatures( |
| {}, {features::kSiteIsolationForCrossOriginOpenerPolicy}); |
| } |
| |
| void SetUpOnMainThread() override { |
| CrossOriginOpenerPolicyBrowserTest::SetUpOnMainThread(); |
| original_client_ = SetBrowserClientForTesting(&browser_client_); |
| |
| // The custom ContentBrowserClient above typically ensures that this test |
| // runs without strict site isolation, but it's still possible to |
| // inadvertently override this when running with --site-per-process on the |
| // command line. This might happen on try bots, so these tests take this |
| // into account to prevent failures, but this is not an intended |
| // configuration for these tests. |
| if (AreAllSitesIsolatedForTesting()) { |
| LOG(WARNING) << "This test should be run without --site-per-process, " |
| << "as it's designed to exercise code paths when strict " |
| << "site isolation is turned off."; |
| } |
| } |
| |
| void TearDownOnMainThread() override { |
| CrossOriginOpenerPolicyBrowserTest::TearDownOnMainThread(); |
| SetBrowserClientForTesting(original_client_); |
| } |
| |
| // A custom ContentBrowserClient to turn off strict site isolation, since |
| // process model differences exist in environments like Android. Note that |
| // kSitePerProcess is a higher-layer feature, so we can't just disable it |
| // here. |
| class NoSiteIsolationContentBrowserClient : public ContentBrowserClient { |
| public: |
| bool ShouldEnableStrictSiteIsolation() override { return false; } |
| }; |
| |
| private: |
| NoSiteIsolationContentBrowserClient browser_client_; |
| raw_ptr<ContentBrowserClient> original_client_ = nullptr; |
| |
| base::test::ScopedFeatureList feature_list_; |
| }; |
| |
| using VirtualBrowsingContextGroupTest = CrossOriginOpenerPolicyBrowserTest; |
| using SoapByDefaultVirtualBrowsingContextGroupTest = |
| CrossOriginOpenerPolicyBrowserTest; |
| |
| int VirtualBrowsingContextGroup(WebContents* wc) { |
| return static_cast<WebContentsImpl*>(wc) |
| ->GetMainFrame() |
| ->virtual_browsing_context_group(); |
| } |
| |
| int SoapByDefaultVirtualBrowsingContextGroup(WebContents* wc) { |
| return static_cast<WebContentsImpl*>(wc) |
| ->GetMainFrame() |
| ->soap_by_default_virtual_browsing_context_group(); |
| } |
| |
| } // namespace |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| NewPopupCOOP_InheritsSameOrigin) { |
| GURL starting_page(https_server()->GetURL( |
| "a.test", "/set-header?cross-origin-opener-policy: same-origin")); |
| EXPECT_TRUE(NavigateToURL(shell(), starting_page)); |
| |
| RenderFrameHostImpl* main_rfh = current_frame_host(); |
| |
| // Create same origin child frame. |
| ASSERT_TRUE(ExecJs(main_rfh, R"( |
| const frame = document.createElement('iframe'); |
| frame.src = '/empty.html'; |
| document.body.appendChild(frame); |
| )")); |
| EXPECT_TRUE(WaitForLoadStop(web_contents())); |
| |
| ShellAddedObserver shell_observer; |
| RenderFrameHostImpl* iframe_rfh = main_rfh->child_at(0)->current_frame_host(); |
| EXPECT_TRUE(ExecJs(iframe_rfh, "window.open('about:blank')")); |
| |
| RenderFrameHostImpl* popup_rfh = |
| static_cast<WebContentsImpl*>(shell_observer.GetShell()->web_contents()) |
| ->GetMainFrame(); |
| |
| EXPECT_EQ(main_rfh->cross_origin_opener_policy(), CoopSameOrigin()); |
| EXPECT_EQ(popup_rfh->cross_origin_opener_policy(), CoopSameOrigin()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| NewPopupCOOP_InheritsSameOriginAllowPopups) { |
| GURL starting_page(https_server()->GetURL( |
| "a.test", |
| "/set-header?cross-origin-opener-policy: same-origin-allow-popups")); |
| EXPECT_TRUE(NavigateToURL(shell(), starting_page)); |
| |
| RenderFrameHostImpl* main_rfh = current_frame_host(); |
| |
| // Create same origin child frame. |
| ASSERT_TRUE(ExecJs(current_frame_host(), R"( |
| const frame = document.createElement('iframe'); |
| frame.src = '/empty.html'; |
| document.body.appendChild(frame); |
| )")); |
| EXPECT_TRUE(WaitForLoadStop(web_contents())); |
| |
| ShellAddedObserver shell_observer; |
| RenderFrameHostImpl* iframe_rfh = main_rfh->child_at(0)->current_frame_host(); |
| EXPECT_TRUE(ExecJs(iframe_rfh, "window.open('about:blank')")); |
| |
| RenderFrameHostImpl* popup_rfh = |
| static_cast<WebContentsImpl*>(shell_observer.GetShell()->web_contents()) |
| ->GetMainFrame(); |
| |
| EXPECT_EQ(main_rfh->cross_origin_opener_policy(), |
| CoopSameOriginAllowPopups()); |
| EXPECT_EQ(popup_rfh->cross_origin_opener_policy(), |
| CoopSameOriginAllowPopups()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| NewPopupCOOP_CrossOriginDoesNotInherit) { |
| GURL starting_page(https_server()->GetURL( |
| "a.test", "/set-header?cross-origin-opener-policy: same-origin")); |
| GURL url_b(https_server()->GetURL("b.test", "/empty.html")); |
| |
| EXPECT_TRUE(NavigateToURL(shell(), starting_page)); |
| |
| RenderFrameHostImpl* main_rfh = current_frame_host(); |
| |
| // Create cross origin child frame. |
| ASSERT_TRUE(ExecJs(main_rfh, JsReplace(R"( |
| const frame = document.createElement('iframe'); |
| frame.src = $1; |
| document.body.appendChild(frame); |
| )", |
| url_b))); |
| EXPECT_TRUE(WaitForLoadStop(web_contents())); |
| |
| ShellAddedObserver shell_observer; |
| RenderFrameHostImpl* iframe_rfh = main_rfh->child_at(0)->current_frame_host(); |
| EXPECT_TRUE(ExecJs(iframe_rfh, "window.open('about:blank')")); |
| |
| RenderFrameHostImpl* popup_rfh = |
| static_cast<WebContentsImpl*>(shell_observer.GetShell()->web_contents()) |
| ->GetMainFrame(); |
| |
| EXPECT_EQ(main_rfh->cross_origin_opener_policy(), CoopSameOrigin()); |
| EXPECT_EQ(popup_rfh->cross_origin_opener_policy(), CoopUnsafeNone()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P( |
| CrossOriginOpenerPolicyBrowserTest, |
| NewPopupCOOP_SameOriginPolicyAndCrossOriginIframeSetsNoopener) { |
| for (const char* header : |
| {"cross-origin-opener-policy: same-origin", |
| "cross-origin-opener-policy: same-origin&cross-origin-embedder-policy: " |
| "require-corp"}) { |
| GURL starting_page( |
| https_server()->GetURL("a.test", std::string("/set-header?") + header)); |
| GURL url_b(https_server()->GetURL("b.test", "/empty.html")); |
| |
| EXPECT_TRUE(NavigateToURL(shell(), starting_page)); |
| |
| RenderFrameHostImpl* main_rfh = current_frame_host(); |
| |
| // Create cross origin child frame. |
| ASSERT_TRUE(ExecJs(main_rfh, JsReplace(R"( |
| const frame = document.createElement('iframe'); |
| frame.src = $1; |
| document.body.appendChild(frame); |
| )", |
| url_b))); |
| EXPECT_TRUE(WaitForLoadStop(web_contents())); |
| |
| ShellAddedObserver new_shell_observer; |
| RenderFrameHostImpl* iframe_rfh = |
| main_rfh->child_at(0)->current_frame_host(); |
| EXPECT_TRUE(ExecJs(iframe_rfh, "window.open('about:blank')")); |
| |
| Shell* new_shell = new_shell_observer.GetShell(); |
| RenderFrameHostImpl* popup_rfh = |
| static_cast<WebContentsImpl*>(new_shell->web_contents()) |
| ->GetMainFrame(); |
| |
| scoped_refptr<SiteInstance> main_rfh_site_instance( |
| main_rfh->GetSiteInstance()); |
| scoped_refptr<SiteInstance> iframe_site_instance( |
| iframe_rfh->GetSiteInstance()); |
| scoped_refptr<SiteInstance> popup_site_instance( |
| popup_rfh->GetSiteInstance()); |
| |
| ASSERT_TRUE(main_rfh_site_instance); |
| ASSERT_TRUE(iframe_site_instance); |
| ASSERT_TRUE(popup_site_instance); |
| EXPECT_FALSE(main_rfh_site_instance->IsRelatedSiteInstance( |
| popup_site_instance.get())); |
| EXPECT_FALSE( |
| iframe_site_instance->IsRelatedSiteInstance(popup_site_instance.get())); |
| |
| // Check that `window.opener` is not set. |
| EXPECT_EQ(true, EvalJs(new_shell, "window.opener == null;")) |
| << "window.opener is set"; |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| BlobInheritsCreatorSameOrigin) { |
| GURL starting_page(https_server()->GetURL( |
| "a.test", "/set-header?cross-origin-opener-policy: same-origin")); |
| EXPECT_TRUE(NavigateToURL(shell(), starting_page)); |
| |
| // Create and open blob. |
| ShellAddedObserver shell_observer; |
| ASSERT_TRUE(ExecJs(current_frame_host(), R"( |
| const blob = new Blob(['foo'], {type : 'text/html'}); |
| const url = URL.createObjectURL(blob); |
| window.open(url); |
| )")); |
| EXPECT_TRUE(WaitForLoadStop(shell_observer.GetShell()->web_contents())); |
| RenderFrameHostImpl* popup_rfh = |
| static_cast<WebContentsImpl*>(shell_observer.GetShell()->web_contents()) |
| ->GetMainFrame(); |
| |
| // COOP and COEP inherited from Blob creator |
| EXPECT_EQ(popup_rfh->cross_origin_opener_policy(), CoopSameOrigin()); |
| EXPECT_EQ(popup_rfh->cross_origin_embedder_policy().value, |
| network::mojom::CrossOriginEmbedderPolicyValue::kNone); |
| EXPECT_FALSE(popup_rfh->GetSiteInstance()->IsCrossOriginIsolated()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| BlobInheritsInitiatorSameOriginPlusCoepCredentialless) { |
| GURL starting_page( |
| https_server()->GetURL("a.test", |
| "/set-header" |
| "?cross-origin-opener-policy: same-origin" |
| "&cross-origin-embedder-policy: credentialless")); |
| EXPECT_TRUE(NavigateToURL(shell(), starting_page)); |
| |
| // Create and open blob. |
| ShellAddedObserver shell_observer; |
| ASSERT_TRUE(ExecJs(current_frame_host(), R"( |
| const blob = new Blob(['foo'], {type : 'text/html'}); |
| const url = URL.createObjectURL(blob); |
| window.open(url); |
| )")); |
| EXPECT_TRUE(WaitForLoadStop(shell_observer.GetShell()->web_contents())); |
| RenderFrameHostImpl* popup_rfh = |
| static_cast<WebContentsImpl*>(shell_observer.GetShell()->web_contents()) |
| ->GetMainFrame(); |
| |
| // COOP and COEP inherited from Blob creator |
| EXPECT_EQ(popup_rfh->cross_origin_opener_policy(), CoopSameOriginPlusCoep()); |
| EXPECT_EQ(popup_rfh->cross_origin_embedder_policy().value, |
| network::mojom::CrossOriginEmbedderPolicyValue::kCredentialless); |
| EXPECT_TRUE(popup_rfh->GetSiteInstance()->IsCrossOriginIsolated()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| BlobInheritsInitiatorSameOriginPlusCoep) { |
| GURL starting_page( |
| https_server()->GetURL("a.test", |
| "/set-header" |
| "?cross-origin-opener-policy: same-origin" |
| "&cross-origin-embedder-policy: require-corp")); |
| EXPECT_TRUE(NavigateToURL(shell(), starting_page)); |
| |
| // Create and open blob. |
| ShellAddedObserver shell_observer; |
| ASSERT_TRUE(ExecJs(current_frame_host(), R"( |
| const blob = new Blob(['foo'], {type : 'text/html'}); |
| const url = URL.createObjectURL(blob); |
| window.open(url); |
| )")); |
| EXPECT_TRUE(WaitForLoadStop(shell_observer.GetShell()->web_contents())); |
| RenderFrameHostImpl* popup_rfh = |
| static_cast<WebContentsImpl*>(shell_observer.GetShell()->web_contents()) |
| ->GetMainFrame(); |
| |
| // COOP and COEP inherited from Blob creator |
| EXPECT_EQ(popup_rfh->cross_origin_opener_policy(), CoopSameOriginPlusCoep()); |
| EXPECT_EQ(popup_rfh->cross_origin_embedder_policy().value, |
| network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp); |
| EXPECT_TRUE(popup_rfh->GetSiteInstance()->IsCrossOriginIsolated()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| BlobInheritsCreatorSameOriginAllowPopups) { |
| GURL starting_page(https_server()->GetURL( |
| "a.test", |
| "/set-header" |
| "?cross-origin-opener-policy: same-origin-allow-popups" |
| "&cross-origin-embedder-policy: require-corp")); |
| EXPECT_TRUE(NavigateToURL(shell(), starting_page)); |
| |
| // Create and open blob. |
| ShellAddedObserver shell_observer; |
| ASSERT_TRUE(ExecJs(current_frame_host(), R"( |
| const blob = new Blob(['foo'], {type : 'text/html'}); |
| const url = URL.createObjectURL(blob); |
| window.open(url); |
| )")); |
| EXPECT_TRUE(WaitForLoadStop(shell_observer.GetShell()->web_contents())); |
| RenderFrameHostImpl* popup_rfh = |
| static_cast<WebContentsImpl*>(shell_observer.GetShell()->web_contents()) |
| ->GetMainFrame(); |
| |
| // COOP and COEP inherited from Blob creator |
| EXPECT_EQ(popup_rfh->cross_origin_opener_policy(), |
| CoopSameOriginAllowPopups()); |
| EXPECT_EQ(popup_rfh->cross_origin_embedder_policy().value, |
| network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp); |
| EXPECT_FALSE(popup_rfh->GetSiteInstance()->IsCrossOriginIsolated()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| BlobInheritsCreatorTopFrameSameOriginCreatorIframeCOEP) { |
| GURL starting_page(https_server()->GetURL( |
| "a.test", "/set-header?cross-origin-opener-policy: same-origin")); |
| GURL iframe_with_coep_url(https_server()->GetURL( |
| "a.test", "/set-header?cross-origin-embedder-policy: require-corp")); |
| |
| EXPECT_TRUE(NavigateToURL(shell(), starting_page)); |
| |
| // Create same origin child frame with COEP |
| ASSERT_TRUE(ExecJs(current_frame_host(), JsReplace(R"( |
| const frame = document.createElement('iframe'); |
| frame.src = $1; |
| document.body.appendChild(frame); |
| )", |
| iframe_with_coep_url))); |
| EXPECT_TRUE(WaitForLoadStop(web_contents())); |
| |
| RenderFrameHostImpl* child_rfh = |
| current_frame_host()->child_at(0)->current_frame_host(); |
| |
| // Create and open blob from iframe. |
| ShellAddedObserver shell_observer; |
| ASSERT_TRUE(ExecJs(child_rfh, R"( |
| const blob = new Blob(['foo'], {type : 'text/html'}); |
| const url = URL.createObjectURL(blob); |
| window.open(url); |
| )")); |
| EXPECT_TRUE(WaitForLoadStop(shell_observer.GetShell()->web_contents())); |
| RenderFrameHostImpl* popup_rfh = |
| static_cast<WebContentsImpl*>(shell_observer.GetShell()->web_contents()) |
| ->GetMainFrame(); |
| |
| // COOP is inherited from creator's top level document, COEP is inherited from |
| // creator. |
| EXPECT_EQ(popup_rfh->cross_origin_opener_policy(), CoopSameOrigin()); |
| EXPECT_EQ(popup_rfh->cross_origin_embedder_policy().value, |
| network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp); |
| EXPECT_FALSE(popup_rfh->GetSiteInstance()->IsCrossOriginIsolated()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| BlobInheritsCreatorNotInitiator) { |
| GURL starting_page(https_server()->GetURL( |
| "a.test", |
| "/set-header" |
| "?cross-origin-opener-policy: same-origin-allow-popups")); |
| EXPECT_TRUE(NavigateToURL(shell(), starting_page)); |
| |
| // Create blob url in main page, which will be used later. |
| // Then open a popup on a document that is same-origin without COOP. |
| ShellAddedObserver first_shell_observer; |
| ASSERT_TRUE(ExecJs(current_frame_host(), R"( |
| const blob = new Blob(['foo'], {type : 'text/html'}); |
| window.url = URL.createObjectURL(blob); |
| window.open("/empty.html"); |
| )")); |
| EXPECT_TRUE(WaitForLoadStop(first_shell_observer.GetShell()->web_contents())); |
| RenderFrameHostImpl* first_popup_rfh = |
| static_cast<WebContentsImpl*>( |
| first_shell_observer.GetShell()->web_contents()) |
| ->GetMainFrame(); |
| |
| // Open blob url created in opener. |
| ShellAddedObserver second_shell_observer; |
| ASSERT_TRUE(ExecJs(first_popup_rfh, R"( |
| window.open(opener.url); |
| )")); |
| EXPECT_TRUE( |
| WaitForLoadStop(second_shell_observer.GetShell()->web_contents())); |
| RenderFrameHostImpl* second_popup_rfh = |
| static_cast<WebContentsImpl*>( |
| second_shell_observer.GetShell()->web_contents()) |
| ->GetMainFrame(); |
| |
| // COOP and COEP inherited from Blob creator (initial window) and not the |
| // initiator (first popup) |
| // TODO(https://crbug.com/1059300) COOP should be inherited from creator and |
| // be same-origin-allow-popups, instead of inheriting from initiator. |
| EXPECT_EQ(second_popup_rfh->cross_origin_opener_policy(), |
| CoopUnsafeNoneWithSoapByDefault()); |
| EXPECT_EQ(second_popup_rfh->cross_origin_embedder_policy().value, |
| network::mojom::CrossOriginEmbedderPolicyValue::kNone); |
| EXPECT_FALSE(second_popup_rfh->GetSiteInstance()->IsCrossOriginIsolated()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| NetworkErrorOnSandboxedPopups) { |
| GURL starting_page(https_server()->GetURL( |
| "a.test", "/cross-origin-opener-policy_sandbox_popup.html")); |
| GURL openee_url = https_server()->GetURL( |
| "a.test", "/set-header?Cross-Origin-Opener-Policy: same-origin"); |
| EXPECT_TRUE(NavigateToURL(shell(), starting_page)); |
| |
| ShellAddedObserver shell_observer; |
| RenderFrameHostImpl* iframe_rfh = |
| current_frame_host()->child_at(0)->current_frame_host(); |
| |
| EXPECT_TRUE(ExecJs(iframe_rfh, JsReplace("window.open($1);", openee_url))); |
| |
| auto* popup_webcontents = |
| static_cast<WebContentsImpl*>(shell_observer.GetShell()->web_contents()); |
| WaitForLoadStop(popup_webcontents); |
| |
| EXPECT_EQ( |
| popup_webcontents->GetController().GetLastCommittedEntry()->GetPageType(), |
| PAGE_TYPE_ERROR); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| NoNetworkErrorOnSandboxedDocuments) { |
| GURL starting_page(https_server()->GetURL( |
| "a.test", "/set-header?Content-Security-Policy: sandbox allow-scripts")); |
| EXPECT_TRUE(NavigateToURL(shell(), starting_page)); |
| EXPECT_NE(current_frame_host()->active_sandbox_flags(), |
| network::mojom::WebSandboxFlags::kNone) |
| << "Document should be sandboxed."; |
| |
| GURL next_page = https_server()->GetURL( |
| "a.test", "/set-header?Cross-Origin-Opener-Policy: same-origin"); |
| |
| EXPECT_TRUE(NavigateToURL(shell(), next_page)); |
| EXPECT_EQ( |
| web_contents()->GetController().GetLastCommittedEntry()->GetPageType(), |
| PAGE_TYPE_NORMAL); |
| } |
| |
| class CrossOriginPolicyHeadersObserver : public WebContentsObserver { |
| public: |
| explicit CrossOriginPolicyHeadersObserver( |
| WebContents* web_contents, |
| network::mojom::CrossOriginEmbedderPolicyValue expected_coep, |
| network::CrossOriginOpenerPolicy expected_coop) |
| : WebContentsObserver(web_contents), |
| expected_coep_(expected_coep), |
| expected_coop_(expected_coop) {} |
| |
| ~CrossOriginPolicyHeadersObserver() override = default; |
| |
| void DidRedirectNavigation(NavigationHandle* navigation_handle) override { |
| // Verify that the COOP/COEP headers were parsed. |
| NavigationRequest* navigation_request = |
| static_cast<NavigationRequest*>(navigation_handle); |
| CHECK(navigation_request->response() |
| ->parsed_headers->cross_origin_embedder_policy.value == |
| expected_coep_); |
| CHECK(navigation_request->response() |
| ->parsed_headers->cross_origin_opener_policy == expected_coop_); |
| } |
| |
| void DidFinishNavigation(NavigationHandle* navigation_handle) override { |
| // Verify that the COOP/COEP headers were parsed. |
| NavigationRequest* navigation_request = |
| static_cast<NavigationRequest*>(navigation_handle); |
| CHECK(navigation_request->response() |
| ->parsed_headers->cross_origin_embedder_policy.value == |
| expected_coep_); |
| CHECK(navigation_request->response() |
| ->parsed_headers->cross_origin_opener_policy == expected_coop_); |
| } |
| |
| private: |
| network::mojom::CrossOriginEmbedderPolicyValue expected_coep_; |
| network::CrossOriginOpenerPolicy expected_coop_; |
| }; |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| RedirectsParseCoopAndCoepHeaders) { |
| GURL redirect_initial_page(https_server()->GetURL( |
| "a.test", "/cross-origin-opener-policy_redirect_initial.html")); |
| GURL redirect_final_page(https_server()->GetURL( |
| "a.test", "/cross-origin-opener-policy_redirect_final.html")); |
| |
| CrossOriginPolicyHeadersObserver obs( |
| web_contents(), |
| network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp, |
| CoopSameOriginPlusCoep()); |
| |
| EXPECT_TRUE( |
| NavigateToURL(shell(), redirect_initial_page, redirect_final_page)); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| CoopIsIgnoredOverHttp) { |
| WebContentsConsoleObserver console_observer(shell()->web_contents()); |
| console_observer.SetPattern("*Cross-Origin-Opener-Policy * ignored*"); |
| |
| GURL non_coop_page(embedded_test_server()->GetURL("a.test", "/title1.html")); |
| GURL coop_page = embedded_test_server()->GetURL( |
| "a.test", "/set-header?Cross-Origin-Opener-Policy: same-origin"); |
| |
| EXPECT_TRUE(NavigateToURL(shell(), non_coop_page)); |
| scoped_refptr<SiteInstance> initial_site_instance( |
| current_frame_host()->GetSiteInstance()); |
| |
| EXPECT_TRUE(NavigateToURL(shell(), coop_page)); |
| if (CanSameSiteMainFrameNavigationsChangeSiteInstances()) { |
| // When ProactivelySwapBrowsingInstance is enabled on same-site navigations, |
| // the SiteInstance will change on same-site navigations (but COOP should |
| // still be ignored). |
| EXPECT_NE(current_frame_host()->GetSiteInstance(), initial_site_instance); |
| } else { |
| EXPECT_EQ(current_frame_host()->GetSiteInstance(), initial_site_instance); |
| } |
| EXPECT_EQ(current_frame_host()->cross_origin_opener_policy(), |
| CoopUnsafeNone()); |
| |
| console_observer.Wait(); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| CoopIsIgnoredOnIframes) { |
| GURL starting_page( |
| https_server()->GetURL("a.com", "/cross_site_iframe_factory.html?a(b)")); |
| GURL iframe_navigation_url = https_server()->GetURL( |
| "b.com", "/set-header?Cross-Origin-Opener-Policy: same-origin"); |
| EXPECT_TRUE(NavigateToURL(shell(), starting_page)); |
| |
| RenderFrameHostImpl* main_rfh = current_frame_host(); |
| FrameTreeNode* iframe_ftn = main_rfh->child_at(0); |
| RenderFrameHostImpl* iframe_rfh = iframe_ftn->current_frame_host(); |
| SiteInstanceImpl* non_coop_iframe_site_instance = |
| iframe_rfh->GetSiteInstance(); |
| |
| // Navigate the iframe same-origin to a document with the COOP header. The |
| // header must be ignored in iframes. |
| EXPECT_TRUE(NavigateToURLFromRenderer(iframe_ftn, iframe_navigation_url)); |
| iframe_rfh = iframe_ftn->current_frame_host(); |
| |
| // We expect the navigation to have used the same SiteInstance that was used |
| // in the first place since they are same origin and COOP is ignored. |
| EXPECT_EQ(iframe_rfh->GetLastCommittedURL(), iframe_navigation_url); |
| EXPECT_EQ(iframe_rfh->GetSiteInstance(), non_coop_iframe_site_instance); |
| |
| // The iframe's COOP value is defaulted to unsafe-none since the iframe is |
| // cross origin with its top frame. |
| EXPECT_EQ(iframe_rfh->cross_origin_opener_policy(), CoopUnsafeNone()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| CoopSameOriginIframeInheritance) { |
| GURL coop_url(embedded_test_server()->GetURL( |
| "/set-header?cross-origin-opener-policy: same-origin")); |
| ASSERT_TRUE(NavigateToURL(shell(), coop_url)); |
| |
| // Create same origin child frame. |
| ASSERT_TRUE(ExecJs(current_frame_host(), R"( |
| const frame = document.createElement('iframe'); |
| frame.src = '/empty.html'; |
| document.body.appendChild(frame); |
| )")); |
| EXPECT_TRUE(WaitForLoadStop(web_contents())); |
| |
| RenderFrameHostImpl* child_rfh = |
| current_frame_host()->child_at(0)->current_frame_host(); |
| |
| // The embedded document has a COOP value that is always inherited from its |
| // top level document if they are same-origin. This has no incidence on the |
| // embeddee but is inherited by the popup opened hereafter. |
| EXPECT_EQ( |
| network::mojom::CrossOriginOpenerPolicyValue::kSameOrigin, |
| child_rfh->policy_container_host()->cross_origin_opener_policy().value); |
| |
| // Create a popup from the iframe. |
| ShellAddedObserver shell_observer; |
| EXPECT_TRUE(ExecJs(child_rfh, R"( |
| w = window.open("about:blank"); |
| )")); |
| WebContentsImpl* popup_webcontents = |
| static_cast<WebContentsImpl*>(shell_observer.GetShell()->web_contents()); |
| RenderFrameHostImpl* popup_rfh = popup_webcontents->GetMainFrame(); |
| |
| // Verify inheritance from the opener: |
| // The second about:blank document of the popup, due to the synchronous |
| // re-navigation to about:blank, inherits COOP from its opener. |
| // When the opener is same-origin with its top-level document, the top-level |
| // document's COOP value (same-origin) is used. |
| // In practice policy container handles the inheritance, taking the value |
| // from the opener directly, which was properly set when the document was |
| // committed. |
| EXPECT_EQ( |
| network::mojom::CrossOriginOpenerPolicyValue::kSameOrigin, |
| popup_rfh->policy_container_host()->cross_origin_opener_policy().value); |
| |
| PolicyContainerHost* popup_initial_policy_container = |
| popup_rfh->policy_container_host(); |
| |
| // Navigate the popup from the iframe to about:blank. |
| EXPECT_TRUE(ExecJs(child_rfh, R"( |
| w.location.href = "about:blank"; |
| )")); |
| EXPECT_TRUE(WaitForLoadStop(popup_webcontents)); |
| popup_rfh = popup_webcontents->GetMainFrame(); |
| |
| // Verify the policy container changed, highlighting that the popup has |
| // navigated to a different about:blank document. |
| EXPECT_NE(popup_initial_policy_container, popup_rfh->policy_container_host()); |
| |
| // Verify inheritance from the initiator: |
| // The navigation to a local scheme inherits COOP from the initiator. When the |
| // initiator is same-origin with its top-level document, the top-level |
| // document's COOP value (same-origin) is used. |
| // In practice policy container handles the inheritance, taking the value |
| // from the initiator directly, which was properly set when the document was |
| // committed. |
| EXPECT_EQ( |
| network::mojom::CrossOriginOpenerPolicyValue::kSameOrigin, |
| popup_rfh->policy_container_host()->cross_origin_opener_policy().value); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| CoopCrossOriginIframeInheritance) { |
| GURL coop_url(embedded_test_server()->GetURL( |
| "/set-header?cross-origin-opener-policy: same-origin-allow-popups")); |
| GURL url_b(embedded_test_server()->GetURL("b.test", "/empty.html")); |
| ASSERT_TRUE(NavigateToURL(shell(), coop_url)); |
| |
| // Create child frame. |
| ASSERT_TRUE(ExecJs(current_frame_host(), JsReplace(R"( |
| const frame = document.createElement('iframe'); |
| frame.src = $1; |
| document.body.appendChild(frame); |
| )", |
| url_b))); |
| EXPECT_TRUE(WaitForLoadStop(web_contents())); |
| |
| RenderFrameHostImpl* child_rfh = |
| current_frame_host()->child_at(0)->current_frame_host(); |
| |
| // The embedded document has a COOP value that is always defaulted when it is |
| // cross origin with its top level document. This has no incidence on the |
| // embeddee but is inherited by the popup opened hereafter. |
| EXPECT_EQ( |
| network::mojom::CrossOriginOpenerPolicyValue::kUnsafeNone, |
| child_rfh->policy_container_host()->cross_origin_opener_policy().value); |
| |
| // Create a popup from the iframe. |
| ShellAddedObserver shell_observer; |
| EXPECT_TRUE(ExecJs(child_rfh, R"( |
| w = window.open("about:blank"); |
| )")); |
| WebContentsImpl* popup_webcontents = |
| static_cast<WebContentsImpl*>(shell_observer.GetShell()->web_contents()); |
| RenderFrameHostImpl* popup_rfh = popup_webcontents->GetMainFrame(); |
| |
| // The second about:blank document of the popup, due to the synchronous |
| // re-navigation to about:blank, inherits COOP from its opener. |
| // When the opener is cross-origin with its top-level document, the COOP value |
| // is defaulted to unsafe-none. |
| // In practice policy container handles the inheritance, taking the value |
| // from the opener directly, which was properly set when the document was |
| // committed. |
| EXPECT_EQ( |
| network::mojom::CrossOriginOpenerPolicyValue::kUnsafeNone, |
| popup_rfh->policy_container_host()->cross_origin_opener_policy().value); |
| |
| PolicyContainerHost* popup_initial_policy_container = |
| popup_rfh->policy_container_host(); |
| |
| // Navigate the popup from the iframe. |
| EXPECT_TRUE(ExecJs(child_rfh, R"( |
| w.location.href = "about:blank"; |
| )")); |
| EXPECT_TRUE(WaitForLoadStop(popup_webcontents)); |
| popup_rfh = popup_webcontents->GetMainFrame(); |
| |
| // Verify the policy container changed, highlighting that the popup has |
| // navigated to a different about:blank document. |
| EXPECT_NE(popup_initial_policy_container, popup_rfh->policy_container_host()); |
| |
| // Verify inheritance from the initiator: |
| // The navigation to a local scheme inherits COOP from the initiator. When the |
| // initiator is cross-origin with its top-level document, the COOP value is |
| // defaulted to unsafe-none. |
| // In practice policy container handles the inheritance, taking the value |
| // from the initiator directly, which was properly set when the document was |
| // committed. |
| EXPECT_EQ( |
| network::mojom::CrossOriginOpenerPolicyValue::kUnsafeNone, |
| popup_rfh->policy_container_host()->cross_origin_opener_policy().value); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| NonCoopPageCrashIntoCoop) { |
| IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess()); |
| GURL non_coop_page(https_server()->GetURL("a.test", "/title1.html")); |
| GURL coop_page = https_server()->GetURL( |
| "a.test", "/set-header?Cross-Origin-Opener-Policy: same-origin"); |
| |
| // Test a crash before the navigation. |
| { |
| // Navigate to a non coop page. |
| EXPECT_TRUE(NavigateToURL(shell(), non_coop_page)); |
| scoped_refptr<SiteInstance> initial_site_instance( |
| current_frame_host()->GetSiteInstance()); |
| |
| // Ensure it has a RenderFrameProxyHost for another cross-site page. |
| GURL non_coop_cross_site_page( |
| https_server()->GetURL("b.test", "/title1.html")); |
| OpenPopup(current_frame_host(), non_coop_cross_site_page, ""); |
| EXPECT_EQ(web_contents() |
| ->GetMainFrame() |
| ->browsing_context_state() |
| ->GetProxyCount(), |
| 1u); |
| |
| // Simulate the renderer process crashing. |
| RenderProcessHost* process = initial_site_instance->GetProcess(); |
| ASSERT_TRUE(process); |
| std::unique_ptr<RenderProcessHostWatcher> crash_observer( |
| new RenderProcessHostWatcher( |
| process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT)); |
| process->Shutdown(0); |
| crash_observer->Wait(); |
| crash_observer.reset(); |
| |
| // Navigate to a COOP page. |
| EXPECT_TRUE(NavigateToURL(shell(), coop_page)); |
| EXPECT_FALSE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance( |
| initial_site_instance.get())); |
| EXPECT_EQ(current_frame_host()->cross_origin_opener_policy(), |
| CoopSameOrigin()); |
| |
| // The COOP page should no longer have any RenderFrameHostProxies. |
| EXPECT_EQ(web_contents() |
| ->GetMainFrame() |
| ->browsing_context_state() |
| ->GetProxyCount(), |
| 0u); |
| } |
| |
| // Test a crash during the navigation. |
| { |
| // Navigate to a non coop page. |
| EXPECT_TRUE(NavigateToURL(shell(), non_coop_page)); |
| scoped_refptr<SiteInstance> initial_site_instance( |
| current_frame_host()->GetSiteInstance()); |
| GURL non_coop_cross_site_page( |
| https_server()->GetURL("b.test", "/title1.html")); |
| |
| // Ensure it has a RenderFrameProxyHost for another cross-site page. |
| OpenPopup(current_frame_host(), non_coop_cross_site_page, ""); |
| EXPECT_EQ(web_contents() |
| ->GetMainFrame() |
| ->browsing_context_state() |
| ->GetProxyCount(), |
| 1u); |
| |
| // Start navigating to a COOP page. |
| TestNavigationManager coop_navigation(web_contents(), coop_page); |
| shell()->LoadURL(coop_page); |
| EXPECT_TRUE(coop_navigation.WaitForRequestStart()); |
| |
| // Simulate the renderer process crashing. |
| RenderProcessHost* process = initial_site_instance->GetProcess(); |
| ASSERT_TRUE(process); |
| std::unique_ptr<RenderProcessHostWatcher> crash_observer( |
| new RenderProcessHostWatcher( |
| process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT)); |
| process->Shutdown(0); |
| crash_observer->Wait(); |
| crash_observer.reset(); |
| |
| // Finish the navigation to the COOP page. |
| coop_navigation.WaitForNavigationFinished(); |
| EXPECT_TRUE(coop_navigation.was_successful()); |
| EXPECT_FALSE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance( |
| initial_site_instance.get())); |
| EXPECT_EQ(current_frame_host()->cross_origin_opener_policy(), |
| CoopSameOrigin()); |
| |
| // The COOP page should no longer have any RenderFrameHostProxies. |
| EXPECT_EQ(web_contents() |
| ->GetMainFrame() |
| ->browsing_context_state() |
| ->GetProxyCount(), |
| 0u); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| CoopPageCrashIntoNonCoop) { |
| IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess()); |
| GURL coop_allow_popups_page(https_server()->GetURL( |
| "a.test", |
| "/set-header?Cross-Origin-Opener-Policy: same-origin-allow-popups")); |
| GURL non_coop_page(https_server()->GetURL( |
| "a.test", "/set-header?Cross-Origin-Opener-Policy: unsafe-none")); |
| GURL cross_origin_non_coop_page( |
| https_server()->GetURL("b.test", "/title1.html")); |
| // Test a crash before the navigation. |
| { |
| // Navigate to a COOP page. |
| EXPECT_TRUE(NavigateToURL(shell(), coop_allow_popups_page)); |
| scoped_refptr<SiteInstance> initial_site_instance( |
| current_frame_host()->GetSiteInstance()); |
| |
| // Ensure it has a RenderFrameProxyHost for another cross-site page. |
| OpenPopup(current_frame_host(), cross_origin_non_coop_page, ""); |
| EXPECT_EQ(web_contents() |
| ->GetMainFrame() |
| ->browsing_context_state() |
| ->GetProxyCount(), |
| 1u); |
| |
| // Simulate the renderer process crashing. |
| RenderProcessHost* process = initial_site_instance->GetProcess(); |
| ASSERT_TRUE(process); |
| std::unique_ptr<RenderProcessHostWatcher> crash_observer( |
| new RenderProcessHostWatcher( |
| process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT)); |
| process->Shutdown(0); |
| crash_observer->Wait(); |
| crash_observer.reset(); |
| |
| // Navigate to a non COOP page. |
| EXPECT_TRUE(NavigateToURL(shell(), non_coop_page)); |
| EXPECT_FALSE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance( |
| initial_site_instance.get())); |
| EXPECT_EQ(current_frame_host()->cross_origin_opener_policy(), |
| CoopUnsafeNone()); |
| |
| // The non COOP page should no longer have any RenderFrameHostProxies. |
| EXPECT_EQ(web_contents() |
| ->GetMainFrame() |
| ->browsing_context_state() |
| ->GetProxyCount(), |
| 0u); |
| } |
| |
| // Test a crash during the navigation. |
| { |
| // Navigate to a COOP page. |
| EXPECT_TRUE(NavigateToURL(shell(), coop_allow_popups_page)); |
| scoped_refptr<SiteInstance> initial_site_instance( |
| current_frame_host()->GetSiteInstance()); |
| |
| // Ensure it has a RenderFrameProxyHost for another cross-site page. |
| OpenPopup(current_frame_host(), cross_origin_non_coop_page, ""); |
| EXPECT_EQ(web_contents() |
| ->GetMainFrame() |
| ->browsing_context_state() |
| ->GetProxyCount(), |
| 1u); |
| |
| // Start navigating to a non COOP page. |
| TestNavigationManager non_coop_navigation(web_contents(), non_coop_page); |
| shell()->LoadURL(non_coop_page); |
| EXPECT_TRUE(non_coop_navigation.WaitForRequestStart()); |
| |
| // Simulate the renderer process crashing. |
| RenderProcessHost* process = initial_site_instance->GetProcess(); |
| ASSERT_TRUE(process); |
| std::unique_ptr<RenderProcessHostWatcher> crash_observer( |
| new RenderProcessHostWatcher( |
| process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT)); |
| process->Shutdown(0); |
| crash_observer->Wait(); |
| crash_observer.reset(); |
| |
| // Finish the navigation to the non COOP page. |
| non_coop_navigation.WaitForNavigationFinished(); |
| EXPECT_TRUE(non_coop_navigation.was_successful()); |
| EXPECT_FALSE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance( |
| initial_site_instance.get())); |
| EXPECT_EQ(current_frame_host()->cross_origin_opener_policy(), |
| CoopUnsafeNone()); |
| |
| // The non COOP page should no longer have any RenderFrameHostProxies. |
| EXPECT_EQ(web_contents() |
| ->GetMainFrame() |
| ->browsing_context_state() |
| ->GetProxyCount(), |
| 0u); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| CoopPageCrashIntoCoop) { |
| IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess()); |
| GURL coop_allow_popups_page(https_server()->GetURL( |
| "a.test", |
| "/set-header?Cross-Origin-Opener-Policy: same-origin-allow-popups")); |
| GURL cross_origin_non_coop_page( |
| https_server()->GetURL("b.test", "/title1.html")); |
| |
| // Test a crash before the navigation. |
| { |
| // Navigate to a COOP page. |
| EXPECT_TRUE(NavigateToURL(shell(), coop_allow_popups_page)); |
| scoped_refptr<SiteInstance> initial_site_instance( |
| current_frame_host()->GetSiteInstance()); |
| EXPECT_EQ(current_frame_host()->cross_origin_opener_policy(), |
| CoopSameOriginAllowPopups()); |
| |
| // Ensure it has a RenderFrameProxyHost for another cross-site page. |
| OpenPopup(current_frame_host(), cross_origin_non_coop_page, ""); |
| |
| EXPECT_EQ(web_contents() |
| ->GetMainFrame() |
| ->browsing_context_state() |
| ->GetProxyCount(), |
| 1u); |
| |
| // Simulate the renderer process crashing. |
| RenderProcessHost* process = initial_site_instance->GetProcess(); |
| ASSERT_TRUE(process); |
| std::unique_ptr<RenderProcessHostWatcher> crash_observer( |
| new RenderProcessHostWatcher( |
| process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT)); |
| process->Shutdown(0); |
| crash_observer->Wait(); |
| crash_observer.reset(); |
| |
| // Navigate to a COOP page. |
| EXPECT_TRUE(NavigateToURL(shell(), coop_allow_popups_page)); |
| EXPECT_TRUE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance( |
| initial_site_instance.get())); |
| EXPECT_EQ(current_frame_host()->cross_origin_opener_policy(), |
| CoopSameOriginAllowPopups()); |
| |
| EXPECT_EQ(web_contents() |
| ->GetMainFrame() |
| ->browsing_context_state() |
| ->GetProxyCount(), |
| 1u); |
| } |
| |
| // Test a crash during the navigation. |
| { |
| // Navigate to a COOP page. |
| EXPECT_TRUE(NavigateToURL(shell(), coop_allow_popups_page)); |
| scoped_refptr<SiteInstance> initial_site_instance( |
| current_frame_host()->GetSiteInstance()); |
| |
| // Ensure it has a RenderFrameProxyHost for another cross-site page. |
| OpenPopup(current_frame_host(), cross_origin_non_coop_page, ""); |
| EXPECT_EQ(web_contents() |
| ->GetMainFrame() |
| ->browsing_context_state() |
| ->GetProxyCount(), |
| 1u); |
| |
| // Start navigating to a COOP page. |
| TestNavigationManager coop_navigation(web_contents(), |
| coop_allow_popups_page); |
| shell()->LoadURL(coop_allow_popups_page); |
| EXPECT_TRUE(coop_navigation.WaitForRequestStart()); |
| |
| // Simulate the renderer process crashing. |
| RenderProcessHost* process = initial_site_instance->GetProcess(); |
| ASSERT_TRUE(process); |
| std::unique_ptr<RenderProcessHostWatcher> crash_observer( |
| new RenderProcessHostWatcher( |
| process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT)); |
| process->Shutdown(0); |
| crash_observer->Wait(); |
| crash_observer.reset(); |
| |
| // Finish the navigation to the COOP page. |
| coop_navigation.WaitForNavigationFinished(); |
| EXPECT_TRUE(coop_navigation.was_successful()); |
| EXPECT_TRUE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance( |
| initial_site_instance.get())); |
| EXPECT_EQ(current_frame_host()->cross_origin_opener_policy(), |
| CoopSameOriginAllowPopups()); |
| |
| EXPECT_EQ(web_contents() |
| ->GetMainFrame() |
| ->browsing_context_state() |
| ->GetProxyCount(), |
| 1u); |
| } |
| } |
| |
| // Reproducer test for https://crbug.com/1264104. |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| BackNavigationCoiToNonCoiAfterCrash) { |
| IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess()); |
| GURL isolated_page( |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp")); |
| GURL non_isolated_page(https_server()->GetURL("a.test", "/title1.html")); |
| |
| // Put a non isolated page in history. |
| EXPECT_TRUE(NavigateToURL(shell(), non_isolated_page)); |
| scoped_refptr<SiteInstanceImpl> non_isolated_site_instance( |
| current_frame_host()->GetSiteInstance()); |
| RenderFrameHostImplWrapper non_isolated_rfh(current_frame_host()); |
| EXPECT_FALSE(non_isolated_site_instance->IsCrossOriginIsolated()); |
| |
| // Keep this alive, simulating not receiving the UnloadACK from the renderer. |
| current_frame_host()->DoNotDeleteForTesting(); |
| |
| // Navigate to an isolated page. |
| EXPECT_TRUE(NavigateToURL(shell(), isolated_page)); |
| scoped_refptr<SiteInstanceImpl> isolated_site_instance( |
| current_frame_host()->GetSiteInstance()); |
| EXPECT_TRUE(isolated_site_instance->IsCrossOriginIsolated()); |
| |
| // Confirm that the page is cached in back/forward cache if available. |
| if (IsBackForwardCacheEnabled()) { |
| EXPECT_TRUE(non_isolated_rfh->IsInBackForwardCache()); |
| } else { |
| EXPECT_FALSE(non_isolated_rfh->IsInBackForwardCache()); |
| } |
| |
| // Simulate the renderer process crashing. |
| RenderProcessHost* process = isolated_site_instance->GetProcess(); |
| ASSERT_TRUE(process); |
| std::unique_ptr<RenderProcessHostWatcher> crash_observer( |
| new RenderProcessHostWatcher( |
| process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT)); |
| process->Shutdown(0); |
| crash_observer->Wait(); |
| crash_observer.reset(); |
| |
| if (IsBackForwardCacheEnabled()) { |
| // Navigate back. Isolated into non-isolated. |
| // The page is cached in back/forward cache. |
| TestNavigationObserver navigation_observer(shell()->web_contents()); |
| web_contents()->GetController().GoBack(); |
| navigation_observer.WaitForNavigationFinished(); |
| EXPECT_EQ(current_frame_host(), non_isolated_rfh.get()); |
| EXPECT_FALSE(non_isolated_rfh.IsRenderFrameDeleted()); |
| } else { |
| // Navigate back. Isolated into non-isolated. |
| // This DCHECKs currently because of https://crbug.com/1264104, |
| // remove the death check and add a simple load wait when the |
| // bug is fixed. |
| EXPECT_DCHECK_DEATH(web_contents()->GetController().GoBack()); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| ProxiesAreRemovedWhenCrossingCoopBoundary) { |
| GURL non_coop_page(https_server()->GetURL("a.test", "/title1.html")); |
| GURL coop_page = https_server()->GetURL( |
| "a.test", "/set-header?Cross-Origin-Opener-Policy: same-origin"); |
| |
| RenderFrameHostManager* main_window_rfhm = |
| web_contents()->GetPrimaryFrameTree().root()->render_manager(); |
| EXPECT_TRUE(NavigateToURL(shell(), non_coop_page)); |
| EXPECT_EQ(main_window_rfhm->current_frame_host() |
| ->browsing_context_state() |
| ->GetProxyCount(), |
| 0u); |
| |
| Shell* popup_shell = OpenPopup(shell(), coop_page, ""); |
| |
| // The main frame should not have the popup referencing it. |
| EXPECT_EQ(main_window_rfhm->current_frame_host() |
| ->browsing_context_state() |
| ->GetProxyCount(), |
| 0u); |
| |
| // It should not have any other related SiteInstance. |
| EXPECT_EQ( |
| current_frame_host()->GetSiteInstance()->GetRelatedActiveContentsCount(), |
| 1u); |
| |
| // The popup should not have the main frame referencing it. |
| FrameTreeNode* popup = |
| static_cast<WebContentsImpl*>(popup_shell->web_contents()) |
| ->GetPrimaryFrameTree() |
| .root(); |
| RenderFrameHostManager* popup_rfhm = popup->render_manager(); |
| EXPECT_EQ(popup_rfhm->current_frame_host() |
| ->browsing_context_state() |
| ->GetProxyCount(), |
| 0u); |
| |
| // The popup should have an empty opener. |
| EXPECT_FALSE(popup->opener()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| ProxiesAreKeptWhenNavigatingFromCoopToCoop) { |
| IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess()); |
| GURL coop_page = https_server()->GetURL( |
| "a.test", "/set-header?Cross-Origin-Opener-Policy: same-origin"); |
| |
| // Navigate to a COOP page. |
| EXPECT_TRUE(NavigateToURL(shell(), coop_page)); |
| scoped_refptr<SiteInstance> initial_site_instance( |
| current_frame_host()->GetSiteInstance()); |
| |
| // Ensure it has a RenderFrameProxyHost for another cross-site page. |
| Shell* popup_shell = OpenPopup(current_frame_host(), coop_page, ""); |
| GURL cross_site_iframe(https_server()->GetURL("b.test", "/title1.html")); |
| TestNavigationManager iframe_navigation(popup_shell->web_contents(), |
| cross_site_iframe); |
| EXPECT_TRUE( |
| ExecJs(popup_shell->web_contents(), |
| JsReplace("const iframe = document.createElement('iframe');" |
| "iframe.src = $1;" |
| "document.body.appendChild(iframe);", |
| cross_site_iframe))); |
| iframe_navigation.WaitForNavigationFinished(); |
| EXPECT_EQ( |
| web_contents()->GetMainFrame()->browsing_context_state()->GetProxyCount(), |
| 1u); |
| |
| // Navigate to a COOP page. |
| EXPECT_TRUE(NavigateToURL(shell(), coop_page)); |
| |
| // The COOP page should still have a RenderFrameProxyHost. |
| EXPECT_EQ( |
| web_contents()->GetMainFrame()->browsing_context_state()->GetProxyCount(), |
| 1u); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| IsolateInNewProcessDespiteLimitReached) { |
| // Set a process limit of 1 for testing. |
| RenderProcessHostImpl::SetMaxRendererProcessCount(1); |
| |
| // Navigate to a starting page. |
| GURL starting_page(https_server()->GetURL("a.test", "/title1.html")); |
| EXPECT_TRUE(NavigateToURL(shell(), starting_page)); |
| |
| // Open a popup with CrossOriginOpenerPolicy and CrossOriginEmbedderPolicy |
| // set. |
| GURL url_openee = |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"); |
| ShellAddedObserver shell_observer; |
| EXPECT_TRUE( |
| ExecJs(current_frame_host(), JsReplace("window.open($1)", url_openee))); |
| |
| auto* popup_webcontents = |
| static_cast<WebContentsImpl*>(shell_observer.GetShell()->web_contents()); |
| EXPECT_TRUE(WaitForLoadStop(popup_webcontents)); |
| |
| // The page and its popup should be in different processes even though the |
| // process limit was reached. |
| EXPECT_NE(current_frame_host()->GetProcess(), |
| popup_webcontents->GetMainFrame()->GetProcess()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| NoProcessReuseForCOOPProcesses) { |
| // Set a process limit of 1 for testing. |
| RenderProcessHostImpl::SetMaxRendererProcessCount(1); |
| |
| // Navigate to a starting page with CrossOriginOpenerPolicy and |
| // CrossOriginEmbedderPolicy set. |
| GURL starting_page = |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"); |
| EXPECT_TRUE(NavigateToURL(shell(), starting_page)); |
| |
| // Open a popup without CrossOriginOpenerPolicy and CrossOriginEmbedderPolicy |
| // set. |
| ShellAddedObserver shell_observer; |
| EXPECT_TRUE(ExecJs(current_frame_host(), "window.open('/title1.html')")); |
| |
| auto* popup_webcontents = |
| static_cast<WebContentsImpl*>(shell_observer.GetShell()->web_contents()); |
| EXPECT_TRUE(WaitForLoadStop(popup_webcontents)); |
| |
| // The page and its popup should be in different processes even though the |
| // process limit was reached. |
| EXPECT_NE(current_frame_host()->GetProcess(), |
| popup_webcontents->GetMainFrame()->GetProcess()); |
| |
| // Navigate to a new page without COOP and COEP. Because of process reuse, it |
| // is placed in the popup process. |
| GURL final_page(https_server()->GetURL("a.test", "/title1.html")); |
| EXPECT_TRUE(NavigateToURL(shell(), final_page)); |
| EXPECT_EQ(current_frame_host()->GetProcess(), |
| popup_webcontents->GetMainFrame()->GetProcess()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| SpeculativeRfhsAndCoop) { |
| GURL non_coop_page(https_server()->GetURL("a.test", "/title1.html")); |
| GURL coop_page = |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"); |
| |
| // Non-COOP into non-COOP. |
| { |
| // Start on a non COOP page. |
| EXPECT_TRUE(NavigateToURL(shell(), non_coop_page)); |
| scoped_refptr<SiteInstance> initial_site_instance( |
| current_frame_host()->GetSiteInstance()); |
| |
| // Navigate to a non COOP page. |
| TestNavigationManager non_coop_navigation(web_contents(), non_coop_page); |
| shell()->LoadURL(non_coop_page); |
| EXPECT_TRUE(non_coop_navigation.WaitForRequestStart()); |
| |
| // TODO(ahemery): RenderDocument will always create a Speculative RFH. |
| // Update these expectations to test the speculative RFH's SI relation when |
| // RenderDocument lands. |
| EXPECT_FALSE(web_contents() |
| ->GetPrimaryFrameTree() |
| .root() |
| ->render_manager() |
| ->speculative_frame_host()); |
| |
| non_coop_navigation.WaitForNavigationFinished(); |
| |
| EXPECT_TRUE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance( |
| initial_site_instance.get())); |
| EXPECT_EQ(current_frame_host()->cross_origin_opener_policy().value, |
| network::mojom::CrossOriginOpenerPolicyValue::kUnsafeNone); |
| } |
| |
| // Non-COOP into COOP. |
| { |
| // Start on a non COOP page. |
| EXPECT_TRUE(NavigateToURL(shell(), non_coop_page)); |
| scoped_refptr<SiteInstance> initial_site_instance( |
| current_frame_host()->GetSiteInstance()); |
| |
| // Navigate to a COOP page. |
| TestNavigationManager coop_navigation(web_contents(), coop_page); |
| shell()->LoadURL(coop_page); |
| EXPECT_TRUE(coop_navigation.WaitForRequestStart()); |
| |
| auto* speculative_rfh = web_contents() |
| ->GetPrimaryFrameTree() |
| .root() |
| ->render_manager() |
| ->speculative_frame_host(); |
| if (CanSameSiteMainFrameNavigationsChangeRenderFrameHosts()) { |
| // When ProactivelySwapBrowsingInstance or RenderDocument is enabled on |
| // same-site main-frame navigations, the navigation will result in a new |
| // RFH, so it will create a pending RFH. |
| EXPECT_TRUE(speculative_rfh); |
| } else { |
| EXPECT_FALSE(speculative_rfh); |
| } |
| |
| coop_navigation.WaitForNavigationFinished(); |
| |
| EXPECT_FALSE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance( |
| initial_site_instance.get())); |
| EXPECT_EQ( |
| current_frame_host()->cross_origin_opener_policy().value, |
| network::mojom::CrossOriginOpenerPolicyValue::kSameOriginPlusCoep); |
| } |
| |
| // COOP into non-COOP. |
| { |
| // Start on a COOP page. |
| EXPECT_TRUE(NavigateToURL(shell(), coop_page)); |
| scoped_refptr<SiteInstance> initial_site_instance( |
| current_frame_host()->GetSiteInstance()); |
| |
| // Navigate to a non COOP page. |
| TestNavigationManager non_coop_navigation(web_contents(), non_coop_page); |
| shell()->LoadURL(non_coop_page); |
| EXPECT_TRUE(non_coop_navigation.WaitForRequestStart()); |
| |
| auto* speculative_rfh = web_contents() |
| ->GetPrimaryFrameTree() |
| .root() |
| ->render_manager() |
| ->speculative_frame_host(); |
| if (CanSameSiteMainFrameNavigationsChangeRenderFrameHosts()) { |
| // When ProactivelySwapBrowsingInstance or RenderDocument is enabled on |
| // same-site main-frame navigations, the navigation will result in a new |
| // RFH, so it will create a pending RFH. |
| EXPECT_TRUE(speculative_rfh); |
| } else { |
| EXPECT_FALSE(speculative_rfh); |
| } |
| |
| non_coop_navigation.WaitForNavigationFinished(); |
| |
| EXPECT_FALSE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance( |
| initial_site_instance.get())); |
| EXPECT_EQ(current_frame_host()->cross_origin_opener_policy().value, |
| network::mojom::CrossOriginOpenerPolicyValue::kUnsafeNone); |
| } |
| |
| // COOP into COOP. |
| { |
| // Start on a COOP page. |
| EXPECT_TRUE(NavigateToURL(shell(), coop_page)); |
| scoped_refptr<SiteInstance> initial_site_instance( |
| current_frame_host()->GetSiteInstance()); |
| |
| // Navigate to a COOP page. |
| TestNavigationManager coop_navigation(web_contents(), coop_page); |
| shell()->LoadURL(coop_page); |
| EXPECT_TRUE(coop_navigation.WaitForRequestStart()); |
| |
| // TODO(ahemery): RenderDocument will always create a Speculative RFH. |
| // Update these expectations to test the speculative RFH's SI relation when |
| // RenderDocument lands. |
| EXPECT_FALSE(web_contents() |
| ->GetPrimaryFrameTree() |
| .root() |
| ->render_manager() |
| ->speculative_frame_host()); |
| |
| coop_navigation.WaitForNavigationFinished(); |
| |
| EXPECT_TRUE(current_frame_host()->GetSiteInstance()->IsRelatedSiteInstance( |
| initial_site_instance.get())); |
| EXPECT_EQ( |
| current_frame_host()->cross_origin_opener_policy().value, |
| network::mojom::CrossOriginOpenerPolicyValue::kSameOriginPlusCoep); |
| } |
| } |
| |
| // https://crbug.com/1266819 suggested that navigating to a cross-origin page |
| // from a cross-origin isolated page is a good reproducer for potential |
| // speculative RFHs + crossOriginIsolated issues. Tests from both a regular and |
| // a crashed frame to also verify with the crash optimization commit. |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| SpeculativeSiteInstanceAndCrossOriginIsolation) { |
| GURL coop_page_a = |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"); |
| GURL page_b(https_server()->GetURL("b.test", "/title1.html")); |
| |
| // Usual navigation. |
| { |
| // Start on a COI page. |
| EXPECT_TRUE(NavigateToURL(shell(), coop_page_a)); |
| scoped_refptr<SiteInstanceImpl> main_site_instance( |
| current_frame_host()->GetSiteInstance()); |
| EXPECT_TRUE(main_site_instance->IsCrossOriginIsolated()); |
| |
| // Popup to a cross-origin page. |
| ShellAddedObserver shell_observer; |
| EXPECT_TRUE(ExecJs(current_frame_host(), |
| JsReplace("window.open($1, 'windowName')", page_b))); |
| WebContents* popup = shell_observer.GetShell()->web_contents(); |
| WaitForLoadStop(popup); |
| |
| RenderFrameHostImpl* popup_frame_host = static_cast<WebContentsImpl*>(popup) |
| ->GetPrimaryFrameTree() |
| .root() |
| ->current_frame_host(); |
| scoped_refptr<SiteInstanceImpl> popup_site_instance( |
| popup_frame_host->GetSiteInstance()); |
| EXPECT_FALSE(popup_site_instance->IsCrossOriginIsolated()); |
| |
| // Verify that COOP enforcement was done properly. |
| EXPECT_FALSE( |
| main_site_instance->IsRelatedSiteInstance(popup_site_instance.get())); |
| EXPECT_EQ(true, EvalJs(popup_frame_host, "window.opener == null;")); |
| EXPECT_EQ("", EvalJs(popup_frame_host, "window.name")); |
| popup->Close(); |
| } |
| |
| // Navigation from a crashed page. |
| { |
| // Start on a COI page. |
| EXPECT_TRUE(NavigateToURL(shell(), coop_page_a)); |
| scoped_refptr<SiteInstanceImpl> main_site_instance( |
| current_frame_host()->GetSiteInstance()); |
| EXPECT_TRUE(main_site_instance->IsCrossOriginIsolated()); |
| |
| // Open an empty popup. |
| ShellAddedObserver shell_observer; |
| EXPECT_TRUE(ExecJs(current_frame_host(), |
| "window.open('about:blank', 'windowName')")); |
| WebContents* popup = shell_observer.GetShell()->web_contents(); |
| WaitForLoadStop(popup); |
| RenderFrameHostImpl* popup_frame_host = static_cast<WebContentsImpl*>(popup) |
| ->GetPrimaryFrameTree() |
| .root() |
| ->current_frame_host(); |
| scoped_refptr<SiteInstanceImpl> popup_site_instance( |
| popup_frame_host->GetSiteInstance()); |
| |
| // Crash it. |
| { |
| RenderProcessHost* process = popup_site_instance->GetProcess(); |
| ASSERT_TRUE(process); |
| auto crash_observer = std::make_unique<RenderProcessHostWatcher>( |
| process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| process->Shutdown(0); |
| crash_observer->Wait(); |
| } |
| |
| // Navigate it to a cross-origin page. |
| EXPECT_TRUE(NavigateToURL(popup, page_b)); |
| WaitForLoadStop(popup); |
| popup_frame_host = static_cast<WebContentsImpl*>(popup) |
| ->GetPrimaryFrameTree() |
| .root() |
| ->current_frame_host(); |
| popup_site_instance = popup_frame_host->GetSiteInstance(); |
| EXPECT_FALSE(popup_site_instance->IsCrossOriginIsolated()); |
| |
| // Verify that COOP enforcement was done properly. |
| EXPECT_FALSE( |
| main_site_instance->IsRelatedSiteInstance(popup_site_instance.get())); |
| EXPECT_EQ(true, EvalJs(popup_frame_host, "window.opener == null;")); |
| EXPECT_EQ("", EvalJs(popup_frame_host, "window.name")); |
| popup->Close(); |
| } |
| } |
| |
| // Try to host into the same cross-origin isolated process, two cross-origin |
| // documents. The second's response sets CSP:sandbox, so its origin is opaque |
| // and derived from the first. |
| // |
| // Variants: |
| // 1. CrossOriginIsolatedOpeneeCspSandbox |
| // 2. CrossOriginIsolatedOpeneeOpenerSandbox |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| CrossOriginIsolatedWithOpeneeCspSandbox) { |
| GURL opener_url = |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"); |
| GURL openee_url = |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp&" |
| "Content-Security-Policy: sandbox"); |
| |
| // Load the first window. |
| EXPECT_TRUE(NavigateToURL(shell(), opener_url)); |
| RenderFrameHostImpl* opener_current_main_document = current_frame_host(); |
| |
| // Load the second window. |
| ShellAddedObserver shell_observer; |
| EXPECT_TRUE( |
| ExecJs(current_frame_host(), JsReplace("window.open($1)", openee_url))); |
| WebContents* popup = shell_observer.GetShell()->web_contents(); |
| WaitForLoadStop(popup); |
| |
| RenderFrameHostImpl* openee_current_main_document = |
| static_cast<WebContentsImpl*>(popup)->GetMainFrame(); |
| |
| // Those documents aren't error pages. |
| EXPECT_EQ(opener_current_main_document->GetLastCommittedURL(), opener_url); |
| EXPECT_EQ(openee_current_main_document->GetLastCommittedURL(), openee_url); |
| EXPECT_EQ(opener_current_main_document->last_http_status_code(), 200); |
| EXPECT_EQ(openee_current_main_document->last_http_status_code(), 200); |
| |
| // We have two main documents in different cross-origin isolated process. |
| EXPECT_NE(opener_current_main_document->GetLastCommittedOrigin(), |
| openee_current_main_document->GetLastCommittedOrigin()); |
| EXPECT_NE(opener_current_main_document->GetProcess(), |
| openee_current_main_document->GetProcess()); |
| EXPECT_NE(opener_current_main_document->GetSiteInstance(), |
| openee_current_main_document->GetSiteInstance()); |
| |
| EXPECT_TRUE( |
| opener_current_main_document->GetSiteInstance()->IsCrossOriginIsolated()); |
| EXPECT_TRUE( |
| openee_current_main_document->GetSiteInstance()->IsCrossOriginIsolated()); |
| } |
| |
| // Variants: |
| // 1. CrossOriginIsolatedOpeneeCspSandbox |
| // 2. CrossOriginIsolatedOpeneeOpenerSandbox |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| CrossOriginIsolatedOpeneeOpenerSandbox) { |
| // The URL used by both the openee and the opener. |
| GURL url = https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp&" |
| "Content-Security-Policy: sandbox allow-scripts allow-popups"); |
| |
| // Load the first window. |
| EXPECT_TRUE(NavigateToURL(shell(), url)); |
| RenderFrameHostImpl* opener_current_main_document = current_frame_host(); |
| |
| // Load the second window. |
| ShellAddedObserver shell_observer; |
| EXPECT_TRUE(ExecJs(current_frame_host(), JsReplace("window.open($1)", url))); |
| WebContents* popup = shell_observer.GetShell()->web_contents(); |
| WaitForLoadStop(popup); |
| |
| RenderFrameHostImpl* openee_current_main_document = |
| static_cast<WebContentsImpl*>(popup)->GetMainFrame(); |
| |
| // Popups with a sandboxing flag, inherited from their opener, are not |
| // allowed to navigate to a document with a Cross-Origin-Opener-Policy that |
| // is not "unsafe-none". As a result, the navigation in the popup ended up |
| // loading an error document. |
| |
| EXPECT_EQ(opener_current_main_document->GetLastCommittedURL(), url); |
| EXPECT_EQ(openee_current_main_document->GetLastCommittedURL(), url); |
| EXPECT_EQ(opener_current_main_document->last_http_status_code(), 200); |
| EXPECT_EQ(openee_current_main_document->last_http_status_code(), 0); |
| |
| EXPECT_NE(opener_current_main_document->GetLastCommittedOrigin(), |
| openee_current_main_document->GetLastCommittedOrigin()); |
| EXPECT_NE(opener_current_main_document->GetProcess(), |
| openee_current_main_document->GetProcess()); |
| EXPECT_NE(opener_current_main_document->GetSiteInstance(), |
| openee_current_main_document->GetSiteInstance()); |
| |
| EXPECT_TRUE( |
| opener_current_main_document->GetSiteInstance()->IsCrossOriginIsolated()); |
| EXPECT_FALSE( |
| openee_current_main_document->GetSiteInstance()->IsCrossOriginIsolated()); |
| } |
| |
| // Navigate in between two documents. Check the virtual browsing context group |
| // is properly updated. |
| IN_PROC_BROWSER_TEST_P(VirtualBrowsingContextGroupTest, Navigation) { |
| const struct { |
| GURL url_a; |
| GURL url_b; |
| bool expect_different_virtual_browsing_context_group; |
| } kTestCases[] = { |
| // non-coop <-> non-coop |
| { |
| // same-origin => keep. |
| https_server()->GetURL("a.test", "/title1.html"), |
| https_server()->GetURL("a.test", "/title2.html"), |
| false, |
| }, |
| { |
| // different-origin => keep. |
| https_server()->GetURL("a.a.test", "/title1.html"), |
| https_server()->GetURL("b.a.test", "/title2.html"), |
| false, |
| }, |
| { |
| // different-site => keep. |
| https_server()->GetURL("a.test", "/title1.html"), |
| https_server()->GetURL("b.test", "/title2.html"), |
| false, |
| }, |
| |
| // non-coop <-> coop. |
| { |
| // same-origin => change. |
| https_server()->GetURL("a.test", "/title1.html"), |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| }, |
| { |
| // different-origin => change. |
| https_server()->GetURL("a.a.test", "/title1.html"), |
| https_server()->GetURL("b.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| }, |
| { |
| // different-site => change. |
| https_server()->GetURL("a.test", "/title1.html"), |
| https_server()->GetURL("b.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| }, |
| |
| // coop <-> coop. |
| { |
| // same-origin => keep. |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| false, |
| }, |
| { |
| // different-origin => change. |
| https_server()->GetURL("a.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL("b.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| }, |
| { |
| // different-site => keep. |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL("b.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| }, |
| |
| // non-coop <-> coop-ro. |
| { |
| // same-origin => change. |
| https_server()->GetURL("a.test", "/title1.html"), |
| https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| }, |
| { |
| // different-origin => change. |
| https_server()->GetURL("a.a.test", "/title1.html"), |
| https_server()->GetURL( |
| "b.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| }, |
| { |
| // different-site => change. |
| https_server()->GetURL("a.test", "/title1.html"), |
| https_server()->GetURL( |
| "b.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| }, |
| |
| // coop-ro <-> coop-ro. |
| { |
| // same-origin => keep. |
| https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| false, |
| }, |
| { |
| // different-origin => change. |
| https_server()->GetURL( |
| "a.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL( |
| "b.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| }, |
| { |
| // different-site => keep. |
| https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL( |
| "b.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| }, |
| |
| // coop <-> coop-ro. |
| { |
| // same-origin => change. |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| }, |
| { |
| // different-origin => change. |
| https_server()->GetURL("a.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL( |
| "b.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| }, |
| { |
| // different-site => change |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL( |
| "b.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| }, |
| // TODO(https://crbug.com/1101339). Test with COEP-RO. |
| // TODO(https://crbug.com/1101339). Test with COOP-RO+COOP. |
| }; |
| |
| for (const auto& test_case : kTestCases) { |
| SCOPED_TRACE(testing::Message() |
| << std::endl |
| << "url_a = " << test_case.url_a << std::endl |
| << "url_b = " << test_case.url_b << std::endl); |
| ASSERT_TRUE(NavigateToURL(shell(), test_case.url_a)); |
| int group_1 = VirtualBrowsingContextGroup(web_contents()); |
| |
| ASSERT_TRUE(NavigateToURL(shell(), test_case.url_b)); |
| int group_2 = VirtualBrowsingContextGroup(web_contents()); |
| |
| ASSERT_TRUE(NavigateToURL(shell(), test_case.url_a)); |
| int group_3 = VirtualBrowsingContextGroup(web_contents()); |
| |
| // Note: Navigating from A to B and navigating from B to A must lead to the |
| // same decision. We check both to avoid adding all the symmetric test |
| // cases. |
| if (test_case.expect_different_virtual_browsing_context_group) { |
| EXPECT_NE(group_1, group_2); // url_a -> url_b. |
| EXPECT_NE(group_2, group_3); // url_a <- url_b. |
| } else { |
| EXPECT_EQ(group_1, group_2); // url_a -> url_b. |
| EXPECT_EQ(group_2, group_3); // url_b <- url_b. |
| } |
| } |
| } |
| |
| // Use window.open(url). Check the virtual browsing context group of the two |
| // window. |
| IN_PROC_BROWSER_TEST_P(VirtualBrowsingContextGroupTest, WindowOpen) { |
| const struct { |
| GURL url_opener; |
| GURL url_openee; |
| bool expect_different_virtual_browsing_context_group; |
| } kTestCases[] = { |
| // Open with no URL => Always keep. |
| { |
| // From non-coop. |
| https_server()->GetURL("a.test", "/title1.html"), |
| GURL(), |
| false, |
| }, |
| { |
| // From coop-ro. |
| https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| GURL(), |
| false, |
| }, |
| { |
| // From coop. |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| GURL(), |
| false, |
| }, |
| |
| // From here, we open a new window with an URL. This is equivalent to: |
| // 1. opening a new window |
| // 2. navigating the new window. |
| // |
| // (1) is tested by the 3 test cases above. |
| // (2) is tested by the test VirtualBrowsingContextGroup. |
| // |
| // Here we are only providing a few test cases to test the sequence 1 & 2. |
| |
| // non-coop opens non-coop. |
| { |
| https_server()->GetURL("a.test", "/title1.html"), |
| https_server()->GetURL("a.test", "/title1.html"), |
| false, |
| }, |
| |
| // non-coop opens coop-ro. |
| { |
| https_server()->GetURL("a.test", "/title1.html"), |
| https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| }, |
| |
| // non-coop opens coop. |
| { |
| https_server()->GetURL("a.test", "/title1.html"), |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| }, |
| |
| // coop opens non-coop. |
| { |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL("a.test", "/title1.html"), |
| true, |
| }, |
| |
| // coop-ro opens coop-ro (same-origin). |
| { |
| https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| false, |
| }, |
| |
| // coop-ro opens coop-ro (different-origin). |
| { |
| https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL( |
| "b.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| }, |
| |
| // TODO(https://crbug.com/1101339). Test with COEP-RO. |
| // TODO(https://crbug.com/1101339). Test with COOP-RO+COOP |
| }; |
| |
| for (const auto& test_case : kTestCases) { |
| SCOPED_TRACE(testing::Message() |
| << std::endl |
| << "url_opener = " << test_case.url_opener << std::endl |
| << "url_openee = " << test_case.url_openee << std::endl); |
| |
| ASSERT_TRUE(NavigateToURL(shell(), test_case.url_opener)); |
| int group_opener = VirtualBrowsingContextGroup(web_contents()); |
| |
| ShellAddedObserver shell_observer; |
| EXPECT_TRUE(ExecJs(current_frame_host(), |
| JsReplace("window.open($1)", test_case.url_openee))); |
| WebContents* popup = shell_observer.GetShell()->web_contents(); |
| // The virtual browser context group will change, only after the popup has |
| // navigated. |
| WaitForLoadStop(popup); |
| int group_openee = VirtualBrowsingContextGroup(popup); |
| |
| if (test_case.expect_different_virtual_browsing_context_group) |
| EXPECT_NE(group_opener, group_openee); |
| else |
| EXPECT_EQ(group_opener, group_openee); |
| |
| popup->Close(); |
| } |
| } |
| |
| namespace { |
| // Use two URLs, |url_a| and |url_b|. One of them at least uses |
| // COOP:same-origin-allow-popups, or COOP-Report-Only:same-origin-allow-popups, |
| // or both (unless soap_by_default is true). |
| // |
| // Test two scenario: |
| // 1. From |url_a|, opens |url_b| |
| // 2. From |url_a|, navigates to |url_b|. |
| // |
| // In both cases, check whether a new virtual browsing context group has been |
| // used or not. |
| // |
| // If soap_by_default is true, then the test will check the soap by default |
| // virtual browsing context group. |
| struct VirtualBcgAllowPopupTestCase { |
| GURL url_a; |
| GURL url_b; |
| bool expect_different_group_window_open; |
| bool expect_different_group_navigation; |
| int (*get_virtual_browsing_context_group)(WebContents*); |
| }; |
| |
| void RunTest(const VirtualBcgAllowPopupTestCase& test_case, Shell* shell) { |
| SCOPED_TRACE(testing::Message() |
| << std::endl |
| << "url_a = " << test_case.url_a << std::endl |
| << "url_b = " << test_case.url_b << std::endl); |
| ASSERT_TRUE(NavigateToURL(shell, test_case.url_a)); |
| int group_initial = |
| test_case.get_virtual_browsing_context_group(shell->web_contents()); |
| |
| ShellAddedObserver shell_observer; |
| EXPECT_TRUE(ExecJs(shell->web_contents()->GetMainFrame(), |
| JsReplace("window.open($1)", test_case.url_b))); |
| WebContents* popup = shell_observer.GetShell()->web_contents(); |
| WaitForLoadStop(popup); |
| int group_openee = test_case.get_virtual_browsing_context_group(popup); |
| |
| ASSERT_TRUE(NavigateToURL(shell, test_case.url_b)); |
| int group_navigate = |
| test_case.get_virtual_browsing_context_group(shell->web_contents()); |
| |
| if (test_case.expect_different_group_window_open) |
| EXPECT_NE(group_initial, group_openee); |
| else |
| EXPECT_EQ(group_initial, group_openee); |
| |
| if (test_case.expect_different_group_navigation) |
| EXPECT_NE(group_initial, group_navigate); |
| else |
| EXPECT_EQ(group_initial, group_navigate); |
| |
| popup->Close(); |
| } |
| |
| } // namespace |
| |
| IN_PROC_BROWSER_TEST_P(VirtualBrowsingContextGroupTest, |
| NonCoopToCoopAllowPopup) { |
| const VirtualBcgAllowPopupTestCase kTestCases[] = { |
| { |
| // same-origin. |
| https_server()->GetURL("a.test", "/title1.html"), |
| https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| true, |
| VirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-origin. |
| https_server()->GetURL("a.a.test", "/title1.html"), |
| https_server()->GetURL( |
| "b.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| true, |
| VirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-site. |
| https_server()->GetURL("a.test", "/title1.html"), |
| https_server()->GetURL( |
| "b.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| true, |
| VirtualBrowsingContextGroup, |
| }, |
| }; |
| for (const auto& test : kTestCases) |
| RunTest(test, shell()); |
| } |
| |
| // coop:same-origin-allow-popup -> coop:none. |
| IN_PROC_BROWSER_TEST_P(VirtualBrowsingContextGroupTest, |
| CoopAllowPopup_NonCoop) { |
| const VirtualBcgAllowPopupTestCase kTestCases[] = { |
| { |
| // same-origin. |
| https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL("a.test", "/title1.html"), |
| false, |
| true, |
| VirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-origin. |
| https_server()->GetURL( |
| "b.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL("a.a.test", "/title1.html"), |
| false, |
| true, |
| VirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-site. |
| https_server()->GetURL( |
| "b.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL("a.test", "/title1.html"), |
| false, |
| true, |
| VirtualBrowsingContextGroup, |
| }, |
| }; |
| for (const auto& test : kTestCases) |
| RunTest(test, shell()); |
| } |
| |
| // coop:none -> coop:same-origin-allow-popup. |
| IN_PROC_BROWSER_TEST_P(VirtualBrowsingContextGroupTest, |
| CoopRoAllowPopup_NonCoop) { |
| const VirtualBcgAllowPopupTestCase kTestCases[] = { |
| { |
| // same-origin. |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: " |
| "same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL("a.test", "/title1.html"), |
| false, |
| true, |
| VirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-origin. |
| https_server()->GetURL("b.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: " |
| "same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL("a.a.test", "/title1.html"), |
| false, |
| true, |
| VirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-site. |
| https_server()->GetURL("b.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: " |
| "same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL("a.test", "/title1.html"), |
| false, |
| true, |
| VirtualBrowsingContextGroup, |
| }, |
| }; |
| for (const auto& test : kTestCases) |
| RunTest(test, shell()); |
| } |
| |
| // coop:same-origin-allow-popup -> coop:same-origin-allow-popup. |
| IN_PROC_BROWSER_TEST_P(VirtualBrowsingContextGroupTest, |
| CoopAllowPopup_CoopAllowPopup) { |
| const VirtualBcgAllowPopupTestCase kTestCases[] = { |
| { |
| // same-origin. |
| https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| false, |
| false, |
| VirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-origin. |
| https_server()->GetURL( |
| "a.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL( |
| "b.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| true, |
| VirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-site. |
| https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL( |
| "b.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| true, |
| VirtualBrowsingContextGroup, |
| }, |
| |
| }; |
| for (const auto& test : kTestCases) |
| RunTest(test, shell()); |
| } |
| |
| // coop:same-origin-allow-popup -> coop-ro:same-origin-allow-popup. |
| IN_PROC_BROWSER_TEST_P(VirtualBrowsingContextGroupTest, |
| CoopAllowPopup_CoopRoAllowPopup) { |
| const VirtualBcgAllowPopupTestCase kTestCases[] = { |
| { |
| // same-origin. |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: " |
| "same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: " |
| "same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| false, |
| true, |
| VirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-origin. |
| https_server()->GetURL("a.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: " |
| "same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL("b.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: " |
| "same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| true, |
| VirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-site. |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: " |
| "same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL("b.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: " |
| "same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| true, |
| VirtualBrowsingContextGroup, |
| }, |
| }; |
| for (const auto& test : kTestCases) |
| RunTest(test, shell()); |
| } |
| |
| // coop-ro:same-origin-allow-popup -> coop:same-origin-allow-popup. |
| IN_PROC_BROWSER_TEST_P(VirtualBrowsingContextGroupTest, |
| CoopRoAllowPopup_CoopAllowPopup) { |
| const VirtualBcgAllowPopupTestCase kTestCases[] = { |
| { |
| // same-origin. |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: " |
| "same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: " |
| "same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| true, |
| VirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-origin. |
| https_server()->GetURL("a.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: " |
| "same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL( |
| "b.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| true, |
| VirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-site. |
| https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL( |
| "b.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| true, |
| true, |
| VirtualBrowsingContextGroup, |
| }, |
| }; |
| |
| for (const auto& test : kTestCases) |
| RunTest(test, shell()); |
| } |
| |
| // coop:same-origin-allow-popup + coop-ro:same-origin-allow-popup -> coop:none. |
| IN_PROC_BROWSER_TEST_P(VirtualBrowsingContextGroupTest, |
| CoopPopupRoSameOrigin_NonCoop) { |
| const VirtualBcgAllowPopupTestCase kTestCases[] = { |
| // coop:allow-popup, coop-ro:same-origin-> no-coop. |
| { |
| // same-origin. |
| https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups&" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL("a.test", "/title1.html"), |
| true, |
| true, |
| VirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-origin. |
| https_server()->GetURL( |
| "a.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups&" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL("b.a.test", "/title1.html"), |
| true, |
| true, |
| VirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-site. |
| https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups&" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"), |
| https_server()->GetURL("b.test", "/title1.html"), |
| true, |
| true, |
| VirtualBrowsingContextGroup, |
| }, |
| }; |
| |
| for (const auto& test : kTestCases) |
| RunTest(test, shell()); |
| } |
| |
| // Navigates in between two pages from a different browsing context group. Then |
| // use the history API to navigate back and forth. Check their virtual browsing |
| // context group isn't restored. |
| // The goal is to spot differences when the BackForwardCache is enabled. See |
| // https://crbug.com/1109648. |
| IN_PROC_BROWSER_TEST_P(VirtualBrowsingContextGroupTest, HistoryNavigation) { |
| GURL url_a = https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"); |
| GURL url_b = https_server()->GetURL( |
| "b.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"); |
| |
| EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
| int group_1 = VirtualBrowsingContextGroup(web_contents()); |
| |
| EXPECT_TRUE(NavigateToURL(shell(), url_b)); |
| int group_2 = VirtualBrowsingContextGroup(web_contents()); |
| |
| web_contents()->GetController().GoBack(); |
| EXPECT_TRUE(WaitForLoadStop(web_contents())); |
| int group_3 = VirtualBrowsingContextGroup(web_contents()); |
| |
| web_contents()->GetController().GoForward(); |
| EXPECT_TRUE(WaitForLoadStop(web_contents())); |
| int group_4 = VirtualBrowsingContextGroup(web_contents()); |
| |
| // No matter whether the BackForwardCache is enabled or not, the navigation in |
| // between the two URLs must always cross a virtual browsing context group. |
| EXPECT_NE(group_1, group_2); |
| EXPECT_NE(group_2, group_3); |
| EXPECT_NE(group_3, group_4); |
| EXPECT_NE(group_1, group_4); |
| |
| // TODO(https://crbug.com/1112256) During history navigation, the virtual |
| // browsing context group must be restored whenever the SiteInstance is |
| // restored. Currently, the SiteInstance is restored, but the virtual browsing |
| // context group is new. |
| |
| if (IsBackForwardCacheEnabled()) { |
| EXPECT_EQ(group_1, group_3); |
| EXPECT_EQ(group_2, group_4); |
| } else { |
| EXPECT_NE(group_1, group_3); |
| EXPECT_NE(group_2, group_4); |
| } |
| } |
| |
| // 1. A1 opens B2 (same virtual browsing context group). |
| // 2. B2 navigates to C3 (different virtual browsing context group). |
| // 3. C3 navigates back to B4 using the history (different virtual browsing |
| // context group). |
| // |
| // A1 and B4 must not be in the same browsing context group. |
| IN_PROC_BROWSER_TEST_P(VirtualBrowsingContextGroupTest, |
| HistoryNavigationWithPopup) { |
| GURL url_a = https_server()->GetURL("a.test", "/title1.html"); |
| GURL url_b = https_server()->GetURL("b.test", "/title1.html"); |
| GURL url_c = https_server()->GetURL( |
| "c.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy-Report-Only: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"); |
| |
| // Navigate to A1. |
| EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
| int group_1 = VirtualBrowsingContextGroup(web_contents()); |
| |
| // A1 opens B2. |
| ShellAddedObserver shell_observer; |
| EXPECT_TRUE( |
| ExecJs(current_frame_host(), JsReplace("window.open($1)", url_b))); |
| WebContents* popup = shell_observer.GetShell()->web_contents(); |
| EXPECT_TRUE(WaitForLoadStop(popup)); |
| int group_2 = VirtualBrowsingContextGroup(popup); |
| |
| // B2 navigates to C3. |
| EXPECT_TRUE(ExecJs(popup, JsReplace("location.href = $1;", url_c))); |
| EXPECT_TRUE(WaitForLoadStop(popup)); |
| int group_3 = VirtualBrowsingContextGroup(popup); |
| |
| // C3 navigates back to B4. |
| EXPECT_TRUE(ExecJs(popup, JsReplace("history.back()"))); |
| EXPECT_TRUE(WaitForLoadStop(popup)); |
| int group_4 = VirtualBrowsingContextGroup(popup); |
| |
| EXPECT_EQ(group_1, group_2); |
| EXPECT_NE(group_2, group_3); |
| EXPECT_NE(group_3, group_4); |
| EXPECT_NE(group_4, group_1); |
| } |
| |
| // A test to make sure that loading a page with COOP/COEP headers doesn't set |
| // is_origin_keyed() on the SiteInstance's SiteInfo. |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| CoopCoepNotOriginKeyed) { |
| GURL isolated_page( |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp")); |
| |
| EXPECT_TRUE(NavigateToURL(shell(), isolated_page)); |
| SiteInstanceImpl* current_si = current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(current_si->IsCrossOriginIsolated()); |
| // Use of COOP/COEP headers should not cause SiteInfo::is_origin_keyed() to |
| // return true. The metrics that track OriginAgentCluster isolation expect |
| // is_origin_keyed() to refer only to the OriginAgentCluster header. |
| EXPECT_FALSE(current_si->GetSiteInfo().requires_origin_keyed_process()); |
| } |
| |
| // This test is flaky on Win, Mac, Linux and ChromeOS: https://crbug.com/1125998 |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \ |
| BUILDFLAG(IS_CHROMEOS) |
| #define MAYBE_CrossOriginIsolatedSiteInstance_MainFrame \ |
| DISABLED_CrossOriginIsolatedSiteInstance_MainFrame |
| #else |
| #define MAYBE_CrossOriginIsolatedSiteInstance_MainFrame \ |
| CrossOriginIsolatedSiteInstance_MainFrame |
| #endif |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| MAYBE_CrossOriginIsolatedSiteInstance_MainFrame) { |
| GURL isolated_page( |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp")); |
| GURL isolated_page_b( |
| https_server()->GetURL("cdn.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp")); |
| GURL non_isolated_page(https_server()->GetURL("a.test", "/title1.html")); |
| |
| // Navigation from/to cross-origin isolated pages. |
| |
| // Initial non cross-origin isolated page. |
| { |
| EXPECT_TRUE(NavigateToURL(shell(), non_isolated_page)); |
| SiteInstanceImpl* current_si = current_frame_host()->GetSiteInstance(); |
| EXPECT_FALSE(current_si->IsCrossOriginIsolated()); |
| } |
| |
| // Navigation to a cross-origin isolated page. |
| { |
| scoped_refptr<SiteInstanceImpl> previous_si = |
| current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(NavigateToURL(shell(), isolated_page)); |
| SiteInstanceImpl* current_si = current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(current_si->IsCrossOriginIsolated()); |
| EXPECT_FALSE(current_si->IsRelatedSiteInstance(previous_si.get())); |
| EXPECT_NE(current_si->GetProcess(), previous_si->GetProcess()); |
| } |
| |
| // Navigation to the same cross-origin isolated page. |
| { |
| scoped_refptr<SiteInstanceImpl> previous_si = |
| current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(NavigateToURL(shell(), isolated_page)); |
| SiteInstanceImpl* current_si = current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(current_si->IsCrossOriginIsolated()); |
| EXPECT_EQ(current_si, previous_si); |
| } |
| |
| // Navigation to a non cross-origin isolated page. |
| { |
| scoped_refptr<SiteInstanceImpl> previous_si = |
| current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(NavigateToURL(shell(), non_isolated_page)); |
| SiteInstanceImpl* current_si = current_frame_host()->GetSiteInstance(); |
| EXPECT_FALSE(current_si->IsCrossOriginIsolated()); |
| EXPECT_FALSE(current_si->IsRelatedSiteInstance(previous_si.get())); |
| EXPECT_NE(current_si->GetProcess(), previous_si->GetProcess()); |
| } |
| |
| // Back navigation from a cross-origin isolated page to a non cross-origin |
| // isolated page. |
| { |
| EXPECT_TRUE(NavigateToURL(shell(), isolated_page)); |
| scoped_refptr<SiteInstanceImpl> cross_origin_isolated_site_instance = |
| current_frame_host()->GetSiteInstance(); |
| |
| EXPECT_TRUE(cross_origin_isolated_site_instance->IsCrossOriginIsolated()); |
| web_contents()->GetController().GoBack(); |
| EXPECT_TRUE(WaitForLoadStop(web_contents())); |
| |
| scoped_refptr<SiteInstanceImpl> non_cross_origin_isolated_site_instance = |
| current_frame_host()->GetSiteInstance(); |
| |
| EXPECT_FALSE( |
| non_cross_origin_isolated_site_instance->IsCrossOriginIsolated()); |
| EXPECT_FALSE(non_cross_origin_isolated_site_instance->IsRelatedSiteInstance( |
| cross_origin_isolated_site_instance.get())); |
| EXPECT_NE(non_cross_origin_isolated_site_instance->GetProcess(), |
| cross_origin_isolated_site_instance->GetProcess()); |
| } |
| |
| // Cross origin navigation in between two cross-origin isolated pages. |
| { |
| EXPECT_TRUE(NavigateToURL(shell(), isolated_page)); |
| scoped_refptr<SiteInstanceImpl> site_instance_1 = |
| current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(NavigateToURL(shell(), isolated_page_b)); |
| SiteInstanceImpl* site_instance_2 = current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(site_instance_1->IsCrossOriginIsolated()); |
| EXPECT_TRUE(site_instance_2->IsCrossOriginIsolated()); |
| EXPECT_FALSE(site_instance_1->IsRelatedSiteInstance(site_instance_2)); |
| EXPECT_NE(site_instance_1->GetProcess(), site_instance_2->GetProcess()); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_P( |
| CrossOriginOpenerPolicyBrowserTest, |
| CrossOriginIsolatedSiteInstance_MainFrameRendererInitiated) { |
| GURL isolated_page( |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp")); |
| GURL isolated_page_b( |
| https_server()->GetURL("cdn.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp")); |
| GURL non_isolated_page(https_server()->GetURL("a.test", "/title1.html")); |
| |
| // Navigation from/to cross-origin isolated pages. |
| |
| // Initial non cross-origin isolated page. |
| { |
| EXPECT_TRUE(NavigateToURL(shell(), non_isolated_page)); |
| SiteInstanceImpl* current_si = current_frame_host()->GetSiteInstance(); |
| EXPECT_FALSE(current_si->IsCrossOriginIsolated()); |
| } |
| |
| // Navigation to a cross-origin isolated page. |
| { |
| scoped_refptr<SiteInstanceImpl> previous_si = |
| current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(NavigateToURLFromRenderer(shell(), isolated_page)); |
| SiteInstanceImpl* current_si = current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(current_si->IsCrossOriginIsolated()); |
| EXPECT_FALSE(current_si->IsRelatedSiteInstance(previous_si.get())); |
| EXPECT_NE(current_si->GetProcess(), previous_si->GetProcess()); |
| } |
| |
| // Navigation to the same cross-origin isolated page. |
| { |
| scoped_refptr<SiteInstanceImpl> previous_si = |
| current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(NavigateToURLFromRenderer(shell(), isolated_page)); |
| SiteInstanceImpl* current_si = current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(current_si->IsCrossOriginIsolated()); |
| EXPECT_EQ(current_si, previous_si); |
| } |
| |
| // Navigation to a non cross-origin isolated page. |
| { |
| scoped_refptr<SiteInstanceImpl> previous_si = |
| current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(NavigateToURLFromRenderer(shell(), non_isolated_page)); |
| SiteInstanceImpl* current_si = current_frame_host()->GetSiteInstance(); |
| EXPECT_FALSE(current_si->IsCrossOriginIsolated()); |
| EXPECT_FALSE(current_si->IsRelatedSiteInstance(previous_si.get())); |
| EXPECT_NE(current_si->GetProcess(), previous_si->GetProcess()); |
| } |
| |
| // Cross origin navigation in between two cross-origin isolated pages. |
| { |
| EXPECT_TRUE(NavigateToURLFromRenderer(shell(), isolated_page)); |
| scoped_refptr<SiteInstanceImpl> site_instance_1 = |
| current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(NavigateToURLFromRenderer(shell(), isolated_page_b)); |
| SiteInstanceImpl* site_instance_2 = current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(site_instance_1->IsCrossOriginIsolated()); |
| EXPECT_TRUE(site_instance_2->IsCrossOriginIsolated()); |
| EXPECT_FALSE(site_instance_1->IsRelatedSiteInstance(site_instance_2)); |
| EXPECT_NE(site_instance_1->GetProcess(), site_instance_2->GetProcess()); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| CrossOriginIsolatedSiteInstance_IFrame) { |
| GURL isolated_page( |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp")); |
| GURL isolated_page_b( |
| https_server()->GetURL("cdn.a.test", |
| "/set-header?" |
| "Cross-Origin-Embedder-Policy: require-corp&" |
| "Cross-Origin-Resource-Policy: cross-origin")); |
| |
| // Initial cross-origin isolated page. |
| EXPECT_TRUE(NavigateToURL(shell(), isolated_page)); |
| SiteInstanceImpl* main_si = current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(main_si->IsCrossOriginIsolated()); |
| |
| // Same origin iframe. |
| { |
| TestNavigationManager same_origin_iframe_navigation(web_contents(), |
| isolated_page); |
| |
| EXPECT_TRUE( |
| ExecJs(web_contents(), |
| JsReplace("const iframe = document.createElement('iframe'); " |
| "iframe.src = $1; " |
| "document.body.appendChild(iframe);", |
| isolated_page))); |
| |
| same_origin_iframe_navigation.WaitForNavigationFinished(); |
| EXPECT_TRUE(same_origin_iframe_navigation.was_successful()); |
| RenderFrameHostImpl* iframe_rfh = |
| current_frame_host()->child_at(0)->current_frame_host(); |
| SiteInstanceImpl* iframe_si = iframe_rfh->GetSiteInstance(); |
| EXPECT_EQ(iframe_si, main_si); |
| } |
| |
| // Cross origin iframe. |
| { |
| TestNavigationManager cross_origin_iframe_navigation(web_contents(), |
| isolated_page_b); |
| |
| EXPECT_TRUE( |
| ExecJs(web_contents(), |
| JsReplace("const iframe = document.createElement('iframe'); " |
| "iframe.src = $1; " |
| "document.body.appendChild(iframe);", |
| isolated_page_b))); |
| |
| cross_origin_iframe_navigation.WaitForNavigationFinished(); |
| EXPECT_TRUE(cross_origin_iframe_navigation.was_successful()); |
| RenderFrameHostImpl* iframe_rfh = |
| current_frame_host()->child_at(1)->current_frame_host(); |
| SiteInstanceImpl* iframe_si = iframe_rfh->GetSiteInstance(); |
| EXPECT_TRUE(iframe_si->IsCrossOriginIsolated()); |
| EXPECT_TRUE(iframe_si->IsRelatedSiteInstance(main_si)); |
| EXPECT_EQ(iframe_si->GetProcess(), main_si->GetProcess()); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| CrossOriginIsolatedSiteInstance_Popup) { |
| GURL isolated_page( |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp")); |
| GURL isolated_page_b( |
| https_server()->GetURL("cdn.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp")); |
| GURL non_isolated_page( |
| embedded_test_server()->GetURL("a.test", "/title1.html")); |
| |
| // Initial cross-origin isolated page. |
| EXPECT_TRUE(NavigateToURL(shell(), isolated_page)); |
| SiteInstanceImpl* main_si = current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(main_si->IsCrossOriginIsolated()); |
| |
| // Open a non isolated popup. |
| { |
| RenderFrameHostImpl* popup_rfh = |
| static_cast<WebContentsImpl*>( |
| OpenPopup(current_frame_host(), non_isolated_page, "") |
| ->web_contents()) |
| ->GetMainFrame(); |
| |
| EXPECT_FALSE(popup_rfh->GetSiteInstance()->IsCrossOriginIsolated()); |
| EXPECT_FALSE(popup_rfh->GetSiteInstance()->IsRelatedSiteInstance( |
| current_frame_host()->GetSiteInstance())); |
| EXPECT_FALSE(popup_rfh->frame_tree_node()->opener()); |
| } |
| |
| // Open an isolated popup. |
| { |
| RenderFrameHostImpl* popup_rfh = |
| static_cast<WebContentsImpl*>( |
| OpenPopup(current_frame_host(), isolated_page, "")->web_contents()) |
| ->GetMainFrame(); |
| |
| EXPECT_TRUE(popup_rfh->GetSiteInstance()->IsCrossOriginIsolated()); |
| EXPECT_EQ(popup_rfh->GetSiteInstance(), |
| current_frame_host()->GetSiteInstance()); |
| } |
| |
| // Open an isolated popup, but cross-origin. |
| { |
| RenderFrameHostImpl* popup_rfh = |
| static_cast<WebContentsImpl*>( |
| OpenPopup(current_frame_host(), isolated_page_b, "") |
| ->web_contents()) |
| ->GetMainFrame(); |
| |
| EXPECT_TRUE(popup_rfh->GetSiteInstance()->IsCrossOriginIsolated()); |
| EXPECT_FALSE(popup_rfh->GetSiteInstance()->IsRelatedSiteInstance( |
| current_frame_host()->GetSiteInstance())); |
| EXPECT_FALSE(popup_rfh->frame_tree_node()->opener()); |
| EXPECT_NE(popup_rfh->GetSiteInstance()->GetProcess(), |
| current_frame_host()->GetSiteInstance()->GetProcess()); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| CrossOriginIsolatedSiteInstance_ErrorPage) { |
| GURL isolated_page( |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp")); |
| GURL non_coep_page(https_server()->GetURL("b.test", |
| "/set-header?" |
| "Access-Control-Allow-Origin: *")); |
| |
| GURL invalid_url( |
| https_server()->GetURL("a.test", "/this_page_does_not_exist.html")); |
| |
| GURL error_url(https_server()->GetURL("a.test", "/page404.html")); |
| |
| // Initial cross-origin isolated page. |
| EXPECT_TRUE(NavigateToURL(shell(), isolated_page)); |
| SiteInstanceImpl* main_si = current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(main_si->IsCrossOriginIsolated()); |
| |
| // Iframe. |
| { |
| TestNavigationManager iframe_navigation(web_contents(), invalid_url); |
| |
| EXPECT_TRUE( |
| ExecJs(web_contents(), |
| JsReplace("const iframe = document.createElement('iframe'); " |
| "iframe.src = $1; " |
| "document.body.appendChild(iframe);", |
| invalid_url))); |
| |
| iframe_navigation.WaitForNavigationFinished(); |
| EXPECT_FALSE(iframe_navigation.was_successful()); |
| RenderFrameHostImpl* iframe_rfh = |
| current_frame_host()->child_at(0)->current_frame_host(); |
| SiteInstanceImpl* iframe_si = iframe_rfh->GetSiteInstance(); |
| // The load of the document with 404 status code is blocked by COEP. |
| // An error page is expected in lieu of that document. |
| EXPECT_EQ(GURL(kUnreachableWebDataURL), |
| EvalJs(iframe_rfh, "document.location.href;")); |
| EXPECT_TRUE(IsExpectedSubframeErrorTransition(main_si, iframe_si)); |
| EXPECT_TRUE(iframe_si->IsCrossOriginIsolated()); |
| } |
| |
| // Iframe with a body added to the HTTP 404. |
| { |
| TestNavigationManager iframe_navigation(web_contents(), error_url); |
| |
| EXPECT_TRUE( |
| ExecJs(web_contents(), |
| JsReplace("const iframe = document.createElement('iframe'); " |
| "iframe.src = $1; " |
| "document.body.appendChild(iframe);", |
| error_url))); |
| |
| iframe_navigation.WaitForNavigationFinished(); |
| EXPECT_FALSE(iframe_navigation.was_successful()); |
| RenderFrameHostImpl* iframe_rfh = |
| current_frame_host()->child_at(0)->current_frame_host(); |
| SiteInstanceImpl* iframe_si = iframe_rfh->GetSiteInstance(); |
| EXPECT_TRUE(IsExpectedSubframeErrorTransition(main_si, iframe_si)); |
| |
| // The load of the document with 404 status code and custom body is blocked |
| // by COEP. An error page is expected in lieu of that document. |
| EXPECT_EQ(GURL(kUnreachableWebDataURL), |
| EvalJs(iframe_rfh, "document.location.href;")); |
| EXPECT_TRUE(iframe_si->IsCrossOriginIsolated()); |
| } |
| |
| // Iframe blocked by coep. |
| { |
| TestNavigationManager iframe_navigation(web_contents(), non_coep_page); |
| |
| EXPECT_TRUE( |
| ExecJs(web_contents(), |
| JsReplace("const iframe = document.createElement('iframe'); " |
| "iframe.src = $1; " |
| "document.body.appendChild(iframe);", |
| non_coep_page))); |
| |
| iframe_navigation.WaitForNavigationFinished(); |
| EXPECT_FALSE(iframe_navigation.was_successful()); |
| RenderFrameHostImpl* iframe_rfh = |
| current_frame_host()->child_at(0)->current_frame_host(); |
| SiteInstanceImpl* iframe_si = iframe_rfh->GetSiteInstance(); |
| EXPECT_TRUE(IsExpectedSubframeErrorTransition(main_si, iframe_si)); |
| EXPECT_TRUE(iframe_si->IsCrossOriginIsolated()); |
| } |
| |
| // Top frame. |
| { |
| scoped_refptr<SiteInstanceImpl> previous_si = |
| current_frame_host()->GetSiteInstance(); |
| EXPECT_FALSE(NavigateToURL(shell(), invalid_url)); |
| SiteInstanceImpl* current_si = current_frame_host()->GetSiteInstance(); |
| EXPECT_FALSE(current_si->IsRelatedSiteInstance(previous_si.get())); |
| EXPECT_NE(current_si->GetProcess(), previous_si->GetProcess()); |
| EXPECT_FALSE(current_si->IsCrossOriginIsolated()); |
| } |
| } |
| |
| // Regression test for https://crbug.com/1226909. |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| NavigatePopupToErrorAndCrash) { |
| GURL isolated_page( |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp")); |
| |
| // Initial cross-origin isolated page. |
| EXPECT_TRUE(NavigateToURL(shell(), isolated_page)); |
| SiteInstanceImpl* main_si = current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(main_si->IsCrossOriginIsolated()); |
| |
| ShellAddedObserver shell_observer; |
| GURL error_url(embedded_test_server()->GetURL("/close-socket")); |
| EXPECT_TRUE(ExecJs(current_frame_host(), |
| JsReplace("window.w = open($1);", error_url))); |
| WebContentsImpl* popup_web_contents = |
| static_cast<WebContentsImpl*>(shell_observer.GetShell()->web_contents()); |
| WaitForLoadStop(popup_web_contents); |
| |
| // The popup should commit an error page with default COOP. |
| EXPECT_EQ(PAGE_TYPE_ERROR, popup_web_contents->GetController() |
| .GetLastCommittedEntry() |
| ->GetPageType()); |
| EXPECT_FALSE(popup_web_contents->GetMainFrame() |
| ->GetSiteInstance() |
| ->IsCrossOriginIsolated()); |
| EXPECT_EQ(CoopUnsafeNone(), |
| popup_web_contents->GetMainFrame()->cross_origin_opener_policy()); |
| |
| url::Origin error_origin = |
| popup_web_contents->GetMainFrame()->GetLastCommittedOrigin(); |
| |
| // Simulate the popup renderer process crashing. |
| RenderProcessHost* popup_process = |
| popup_web_contents->GetMainFrame()->GetProcess(); |
| EXPECT_NE(popup_process, current_frame_host()->GetProcess()); |
| |
| ASSERT_TRUE(popup_process); |
| { |
| RenderProcessHostWatcher crash_observer( |
| popup_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| popup_process->Shutdown(0); |
| crash_observer.Wait(); |
| } |
| |
| // Try to navigate the popup. This should not be possible, since the opener |
| // relationship should be closed. |
| EXPECT_TRUE( |
| ExecJs(current_frame_host(), "window.w.location = 'about:blank';")); |
| WaitForLoadStop(popup_web_contents); |
| |
| // The popup should not have navigated. |
| EXPECT_EQ(error_origin, |
| popup_web_contents->GetMainFrame()->GetLastCommittedOrigin()); |
| EXPECT_FALSE(popup_web_contents->GetMainFrame() |
| ->GetSiteInstance() |
| ->IsCrossOriginIsolated()); |
| EXPECT_EQ(CoopUnsafeNone(), |
| popup_web_contents->GetMainFrame()->cross_origin_opener_policy()); |
| } |
| |
| // Regression test for https://crbug.com/1239540. |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| ReloadCrossOriginIsolatedPageWhileOffline) { |
| GURL isolated_page( |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp")); |
| |
| // Initial cross origin isolated page. |
| EXPECT_TRUE(NavigateToURL(shell(), isolated_page)); |
| SiteInstanceImpl* main_si = current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(main_si->IsCrossOriginIsolated()); |
| |
| // Simulate being offline by failing all network requests. |
| auto url_loader_interceptor = |
| std::make_unique<content::URLLoaderInterceptor>(base::BindRepeating( |
| [](content::URLLoaderInterceptor::RequestParams* params) { |
| network::URLLoaderCompletionStatus status; |
| status.error_code = net::Error::ERR_CONNECTION_FAILED; |
| params->client->OnComplete(status); |
| return true; |
| })); |
| |
| // Reload and end up with an error page to verify we do not violate any cross |
| // origin isolation invariant. |
| ReloadBlockUntilNavigationsComplete(shell(), 1); |
| } |
| |
| // Regression test for https://crbug.com/1239540. |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| ReloadCoopPageWhileOffline) { |
| GURL isolated_page( |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin")); |
| |
| // Initial coop isolated page. |
| EXPECT_TRUE(NavigateToURL(shell(), isolated_page)); |
| RenderFrameHostImpl* main_rfh = current_frame_host(); |
| EXPECT_EQ(main_rfh->cross_origin_opener_policy(), CoopSameOrigin()); |
| |
| // Simulate being offline by failing all network requests. |
| auto url_loader_interceptor = |
| std::make_unique<content::URLLoaderInterceptor>(base::BindRepeating( |
| [](content::URLLoaderInterceptor::RequestParams* params) { |
| network::URLLoaderCompletionStatus status; |
| status.error_code = net::Error::ERR_CONNECTION_FAILED; |
| params->client->OnComplete(status); |
| return true; |
| })); |
| |
| // Reload and end up with an error page to verify we do not violate any cross |
| // origin isolation invariant. |
| ReloadBlockUntilNavigationsComplete(shell(), 1); |
| } |
| |
| // Regression test for https://crbug.com/1239540. |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| BackNavigationToCrossOriginIsolatedPageWhileOffline) { |
| GURL isolated_page( |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp")); |
| |
| GURL same_origin_isolated_page( |
| https_server()->GetURL("a.test", "/cross-origin-isolated.html")); |
| |
| // Put the initial isolated page in history. |
| EXPECT_TRUE(NavigateToURL(shell(), isolated_page)); |
| SiteInstanceImpl* main_si = current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(main_si->IsCrossOriginIsolated()); |
| |
| // This test relies on actually doing the back navigation from network. |
| // We disable BFCache on the initial to ensure that happens. |
| DisableBFCacheForRFHForTesting(current_frame_host()->GetGlobalId()); |
| |
| // Navigate to a same origin isolated page, staying in the same |
| // BrowsingInstance. This is also ensured by having the BFCache disabled on |
| // the initial page, avoiding special same-site proactive swaps. |
| EXPECT_TRUE(NavigateToURL(shell(), same_origin_isolated_page)); |
| main_si = current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(main_si->IsCrossOriginIsolated()); |
| |
| // Simulate being offline by failing all network requests. |
| auto url_loader_interceptor = |
| std::make_unique<content::URLLoaderInterceptor>(base::BindRepeating( |
| [](content::URLLoaderInterceptor::RequestParams* params) { |
| network::URLLoaderCompletionStatus status; |
| status.error_code = net::Error::ERR_CONNECTION_FAILED; |
| params->client->OnComplete(status); |
| return true; |
| })); |
| |
| // Go back and end up with an error page to verify we do not violate any cross |
| // origin isolation invariant. |
| web_contents()->GetController().GoBack(); |
| EXPECT_FALSE(WaitForLoadStop(web_contents())); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| CrossOriginRedirectHasProperCrossOriginIsolatedState) { |
| GURL non_isolated_page( |
| embedded_test_server()->GetURL("a.test", "/title1.html")); |
| |
| GURL isolated_page( |
| https_server()->GetURL("c.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp")); |
| |
| GURL redirect_isolated_page(https_server()->GetURL( |
| "b.test", "/redirect-with-coop-coep-headers?" + isolated_page.spec())); |
| |
| EXPECT_TRUE(NavigateToURL(shell(), non_isolated_page)); |
| SiteInstanceImpl* current_si = current_frame_host()->GetSiteInstance(); |
| EXPECT_FALSE(current_si->IsCrossOriginIsolated()); |
| |
| EXPECT_TRUE(NavigateToURL(shell(), redirect_isolated_page, isolated_page)); |
| current_si = current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(current_si->IsCrossOriginIsolated()); |
| EXPECT_TRUE( |
| current_si->GetWebExposedIsolationInfo().origin().IsSameOriginWith( |
| url::Origin::Create(isolated_page))); |
| } |
| |
| // Reproducer test for https://crbug.com/1150938. |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| MainFrameA_IframeB_Opens_WindowA) { |
| GURL isolated_page( |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp")); |
| GURL isolated_page_b( |
| https_server()->GetURL("cdn.a.test", |
| "/set-header?" |
| "Cross-Origin-Embedder-Policy: require-corp&" |
| "Cross-Origin-Resource-Policy: cross-origin")); |
| |
| // Initial cross-origin isolated page. |
| EXPECT_TRUE(NavigateToURL(shell(), isolated_page)); |
| SiteInstanceImpl* main_si = current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(main_si->IsCrossOriginIsolated()); |
| |
| TestNavigationManager cross_origin_iframe_navigation(web_contents(), |
| isolated_page_b); |
| |
| EXPECT_TRUE( |
| ExecJs(web_contents(), |
| JsReplace("const iframe = document.createElement('iframe'); " |
| "iframe.src = $1; " |
| "document.body.appendChild(iframe);", |
| isolated_page_b))); |
| |
| cross_origin_iframe_navigation.WaitForNavigationFinished(); |
| EXPECT_TRUE(cross_origin_iframe_navigation.was_successful()); |
| RenderFrameHostImpl* iframe_rfh = |
| current_frame_host()->child_at(0)->current_frame_host(); |
| SiteInstanceImpl* iframe_si = iframe_rfh->GetSiteInstance(); |
| EXPECT_TRUE(iframe_si->IsCrossOriginIsolated()); |
| EXPECT_TRUE(iframe_si->IsRelatedSiteInstance(main_si)); |
| EXPECT_EQ(iframe_si->GetProcess(), main_si->GetProcess()); |
| |
| // Open an isolated popup, but cross-origin. |
| { |
| RenderFrameHostImpl* popup_rfh = |
| static_cast<WebContentsImpl*>( |
| OpenPopup(iframe_rfh, isolated_page, "", "", false)->web_contents()) |
| ->GetMainFrame(); |
| |
| EXPECT_TRUE(popup_rfh->GetSiteInstance()->IsCrossOriginIsolated()); |
| EXPECT_FALSE(popup_rfh->GetSiteInstance()->IsRelatedSiteInstance( |
| current_frame_host()->GetSiteInstance())); |
| EXPECT_FALSE(popup_rfh->frame_tree_node()->opener()); |
| EXPECT_NE(popup_rfh->GetSiteInstance()->GetProcess(), |
| current_frame_host()->GetSiteInstance()->GetProcess()); |
| } |
| } |
| |
| // Regression test for https://crbug.com/1183571. This used to crash. |
| // A grand child, same-origin with its parent, but cross-origin with the main |
| // document is accessing a popup. |
| // |
| // TODO(arthursonzogni): Add a similar WPT test. |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| GrandChildAccessCrash1183571) { |
| GURL a_url_coop(https_server()->GetURL( |
| "a.test", |
| "/set-header?Cross-Origin-Opener-Policy-Report-Only: same-origin")); |
| GURL b_url(https_server()->GetURL("b.test", "/empty.html")); |
| GURL c_url(https_server()->GetURL("c.test", "/empty.html")); |
| |
| // 1. Start from COOP-Report-Only:same-origin. (a.test COOP-RO) |
| EXPECT_TRUE(NavigateToURL(shell(), a_url_coop)); |
| RenderFrameHostImpl* opener_rfh = current_frame_host(); |
| |
| // 2. Add a window in a different (virtual) browsing context group. |
| // |
| // The new popup won't be used, but it is created to avoid the |
| // DOMWindow::ReportCoopAccess() fast early return. The original bug won't |
| // reproduce without this. |
| { |
| ShellAddedObserver shell_observer; |
| EXPECT_TRUE(ExecJs(opener_rfh, JsReplace(R"( |
| window.open($1); |
| )", |
| b_url))); |
| WaitForLoadStop(shell_observer.GetShell()->web_contents()); |
| } |
| |
| // 3. Insert a cross-origin iframe. (b.test) |
| EXPECT_TRUE(ExecJs(opener_rfh, JsReplace(R"( |
| const iframe = document.createElement("iframe"); |
| iframe.src = $1; |
| document.body.appendChild(iframe); |
| )", |
| b_url))); |
| WaitForLoadStop(web_contents()); |
| RenderFrameHostImpl* opener_child_rfh = |
| opener_rfh->child_at(0)->current_frame_host(); |
| |
| // 4. Insert a grand-child iframe (b.test). |
| EXPECT_TRUE(ExecJs(opener_child_rfh, JsReplace(R"( |
| const iframe = document.createElement("iframe"); |
| iframe.src = $1; |
| document.body.appendChild(iframe); |
| )", |
| b_url))); |
| WaitForLoadStop(web_contents()); |
| RenderFrameHostImpl* opener_grand_child_rfh = |
| opener_child_rfh->child_at(0)->current_frame_host(); |
| |
| // 5. The grand child creates a new cross-origin popup... |
| ShellAddedObserver shell_observer; |
| EXPECT_TRUE(ExecJs(opener_grand_child_rfh, JsReplace(R"( |
| window.openee = window.open($1); |
| )", |
| c_url))); |
| WaitForLoadStop(shell_observer.GetShell()->web_contents()); |
| |
| // 6. ... and tries to access it. |
| EXPECT_EQ("I didn't crash", EvalJs(opener_grand_child_rfh, R"( |
| window.openee.closed; |
| "I didn't crash"; |
| )")); |
| } |
| |
| // This test is a reproducer for https://crbug.com/1305394. |
| // This test is flaky on Mac: https://crbug.com/1319301 |
| #if BUILDFLAG(IS_MAC) |
| #define MAYBE_CrossOriginIframeCoopBypass DISABLED_CrossOriginIframeCoopBypass |
| #else |
| #define MAYBE_CrossOriginIframeCoopBypass CrossOriginIframeCoopBypass |
| #endif |
| IN_PROC_BROWSER_TEST_P(CrossOriginOpenerPolicyBrowserTest, |
| MAYBE_CrossOriginIframeCoopBypass) { |
| // This test requires that a cross-origin iframe be placed in its own |
| // process. It is irrelevant without strict site isolation. |
| if (!SiteIsolationPolicy::UseDedicatedProcessesForAllSites()) |
| return; |
| |
| GURL non_coop_page(https_server()->GetURL("a.test", "/title1.html")); |
| GURL cross_origin_non_coop_page( |
| https_server()->GetURL("b.test", "/title1.html")); |
| GURL coop_page(https_server()->GetURL( |
| "a.test", "/set-header?cross-origin-opener-policy: same-origin")); |
| |
| // Get an initial non-COOP page with an empty popup. |
| EXPECT_TRUE(NavigateToURL(shell(), non_coop_page)); |
| RenderFrameHostImpl* initial_main_rfh = current_frame_host(); |
| |
| ShellAddedObserver shell_observer; |
| EXPECT_TRUE( |
| ExecJs(initial_main_rfh, JsReplace("window.open($1)", non_coop_page))); |
| WebContentsImpl* popup = |
| static_cast<WebContentsImpl*>(shell_observer.GetShell()->web_contents()); |
| RenderFrameHostImpl* popup_rfh = popup->GetMainFrame(); |
| |
| // At this stage we have a single SiteInstance used both for the main page and |
| // the same-site popup. |
| SiteInstanceImpl* initial_main_si = initial_main_rfh->GetSiteInstance(); |
| SiteInstanceImpl* popup_si = popup_rfh->GetSiteInstance(); |
| EXPECT_EQ(initial_main_si, popup_si); |
| RenderProcessHost* process_A = initial_main_si->GetProcess(); |
| |
| // The popup then navigates the opener to a COOP page. |
| EXPECT_TRUE(ExecJs(popup_rfh, JsReplace("opener.location = $1", coop_page))); |
| EXPECT_TRUE(WaitForLoadStop(web_contents())); |
| |
| // This should trigger a BrowsingInstance swap. The main frame gets a new |
| // unrelated BrowsingInstance, and clears the opener. |
| // Note: We need to wait for the RenderView deletion to be propagated in the |
| // renderer for window.opener to be cleared. To avoid flakes, we check the |
| // opener at the end of this test. |
| RenderFrameHostImpl* main_rfh = current_frame_host(); |
| SiteInstanceImpl* main_si = main_rfh->GetSiteInstance(); |
| RenderProcessHost* process_B = main_si->GetProcess(); |
| EXPECT_FALSE(popup_si->IsRelatedSiteInstance(main_si)); |
| |
| // The popup still uses process A, but the main page now uses a different |
| // process. No proxy should remain between the two site instances as the |
| // opener link has been cut. |
| EXPECT_EQ(process_A, popup_si->GetProcess()); |
| EXPECT_NE(process_B, process_A); |
| EXPECT_TRUE(popup_rfh->frame_tree_node() |
| ->render_manager() |
| ->GetAllProxyHostsForTesting() |
| .empty()); |
| EXPECT_TRUE(main_rfh->frame_tree_node() |
| ->render_manager() |
| ->GetAllProxyHostsForTesting() |
| .empty()); |
| |
| // Load an iframe that is cross-origin to the top frame's opener. |
| ASSERT_TRUE(ExecJs(popup_rfh, JsReplace(R"( |
| const frame = document.createElement('iframe'); |
| frame.src = $1; |
| document.body.appendChild(frame); |
| )", |
| cross_origin_non_coop_page))); |
| EXPECT_TRUE(WaitForLoadStop(popup)); |
| RenderFrameHostImpl* iframe_rfh = |
| popup_rfh->child_at(0)->current_frame_host(); |
| SiteInstanceImpl* iframe_si = iframe_rfh->GetSiteInstance(); |
| |
| // The iframe being cross-origin, it is put in a different but related |
| // SiteInstance. |
| EXPECT_TRUE(iframe_si->IsRelatedSiteInstance(popup_si)); |
| EXPECT_FALSE(iframe_si->IsRelatedSiteInstance(main_si)); |
| |
| // We end up with the main window, the main popup frame and the iframe all |
| // living in their own process. We should only have proxies from the popup |
| // main frame to iframe and vice versa. Opener links should stay severed. |
| RenderProcessHost* process_C = iframe_si->GetProcess(); |
| EXPECT_NE(process_C, process_A); |
| EXPECT_NE(process_C, process_B); |
| EXPECT_EQ(1u, iframe_rfh->frame_tree_node() |
| ->render_manager() |
| ->GetAllProxyHostsForTesting() |
| .size()); |
| EXPECT_EQ(1u, popup_rfh->frame_tree_node() |
| ->render_manager() |
| ->GetAllProxyHostsForTesting() |
| .size()); |
| |
| // The opener should not be reachable either from the popup main frame nor the |
| // popup iframe. |
| EXPECT_EQ(true, EvalJs(popup_rfh, "opener == null")); |
| EXPECT_EQ(true, EvalJs(iframe_rfh, "parent.opener == null")); |
| } |
| |
| // TODO(https://crbug.com/1101339). Test inheritance of the virtual browsing |
| // context group when using window.open from an iframe, same-origin and |
| // cross-origin. |
| |
| static auto kTestParams = |
| testing::Combine(testing::ValuesIn(RenderDocumentFeatureLevelValues()), |
| testing::Bool()); |
| INSTANTIATE_TEST_SUITE_P(All, |
| CrossOriginOpenerPolicyBrowserTest, |
| kTestParams, |
| CrossOriginOpenerPolicyBrowserTest::DescribeParams); |
| INSTANTIATE_TEST_SUITE_P(All, |
| VirtualBrowsingContextGroupTest, |
| kTestParams, |
| CrossOriginOpenerPolicyBrowserTest::DescribeParams); |
| INSTANTIATE_TEST_SUITE_P(All, |
| NoSharedArrayBufferByDefault, |
| kTestParams, |
| CrossOriginOpenerPolicyBrowserTest::DescribeParams); |
| INSTANTIATE_TEST_SUITE_P(All, |
| SoapByDefaultVirtualBrowsingContextGroupTest, |
| kTestParams, |
| CrossOriginOpenerPolicyBrowserTest::DescribeParams); |
| INSTANTIATE_TEST_SUITE_P(All, |
| SameOriginAllowPopupsPlusCoepBrowserTest, |
| kTestParams, |
| CrossOriginOpenerPolicyBrowserTest::DescribeParams); |
| INSTANTIATE_TEST_SUITE_P(All, |
| NoSiteIsolationCrossOriginIsolationBrowserTest, |
| kTestParams, |
| CrossOriginOpenerPolicyBrowserTest::DescribeParams); |
| |
| IN_PROC_BROWSER_TEST_P(NoSharedArrayBufferByDefault, BaseCase) { |
| GURL url = https_server()->GetURL("a.test", "/empty.html"); |
| EXPECT_TRUE(NavigateToURL(shell(), url)); |
| EXPECT_EQ(false, EvalJs(current_frame_host(), "self.crossOriginIsolated")); |
| EXPECT_EQ(false, |
| EvalJs(current_frame_host(), "'SharedArrayBuffer' in globalThis")); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(NoSharedArrayBufferByDefault, CoopCoepIsolated) { |
| GURL url = |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"); |
| EXPECT_TRUE(NavigateToURL(shell(), url)); |
| EXPECT_EQ(true, EvalJs(current_frame_host(), "self.crossOriginIsolated")); |
| EXPECT_EQ(true, |
| EvalJs(current_frame_host(), "'SharedArrayBuffer' in globalThis")); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(NoSharedArrayBufferByDefault, |
| CoopCoepTransferSharedArrayBufferToIframe) { |
| CHECK(!base::FeatureList::IsEnabled(features::kSharedArrayBuffer)); |
| GURL url = |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"); |
| EXPECT_TRUE(NavigateToURL(shell(), url)); |
| EXPECT_TRUE(ExecJs(current_frame_host(), |
| "g_iframe = document.createElement('iframe');" |
| "g_iframe.src = location.href;" |
| "document.body.appendChild(g_iframe);")); |
| WaitForLoadStop(web_contents()); |
| |
| RenderFrameHostImpl* main_document = current_frame_host(); |
| RenderFrameHostImpl* sub_document = |
| current_frame_host()->child_at(0)->current_frame_host(); |
| |
| EXPECT_EQ(true, EvalJs(main_document, "self.crossOriginIsolated")); |
| EXPECT_EQ(true, EvalJs(sub_document, "self.crossOriginIsolated")); |
| |
| EXPECT_TRUE(ExecJs(sub_document, R"( |
| g_sab_size = new Promise(resolve => { |
| addEventListener("message", event => resolve(event.data.byteLength)); |
| }); |
| )", |
| EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); |
| |
| EXPECT_TRUE(ExecJs(main_document, R"( |
| const sab = new SharedArrayBuffer(1234); |
| g_iframe.contentWindow.postMessage(sab, "*"); |
| )")); |
| |
| EXPECT_EQ(1234, EvalJs(sub_document, "g_sab_size")); |
| } |
| |
| // Transfer a SharedArrayBuffer in between two COOP+COEP document with a |
| // parent/child relationship. The child has set Permissions-Policy: |
| // cross-origin-isolated=(). As a result, it can't receive the object. |
| IN_PROC_BROWSER_TEST_P( |
| NoSharedArrayBufferByDefault, |
| CoopCoepTransferSharedArrayBufferToNoCrossOriginIsolatedIframe) { |
| CHECK(!base::FeatureList::IsEnabled(features::kSharedArrayBuffer)); |
| GURL main_url = |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"); |
| GURL iframe_url = |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Embedder-Policy: require-corp&" |
| "Cross-Origin-Resource-Policy: cross-origin&" |
| "Permissions-Policy: cross-origin-isolated%3D()"); |
| EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| EXPECT_TRUE(ExecJs(current_frame_host(), |
| JsReplace("g_iframe = document.createElement('iframe');" |
| "g_iframe.src = $1;" |
| "document.body.appendChild(g_iframe);", |
| iframe_url))); |
| WaitForLoadStop(web_contents()); |
| |
| RenderFrameHostImpl* main_document = current_frame_host(); |
| RenderFrameHostImpl* sub_document = |
| current_frame_host()->child_at(0)->current_frame_host(); |
| |
| EXPECT_EQ(true, EvalJs(main_document, "self.crossOriginIsolated")); |
| EXPECT_EQ(false, EvalJs(sub_document, "self.crossOriginIsolated")); |
| |
| auto postSharedArrayBuffer = EvalJs(main_document, R"( |
| const sab = new SharedArrayBuffer(1234); |
| g_iframe.contentWindow.postMessage(sab,"*"); |
| )"); |
| |
| EXPECT_THAT(postSharedArrayBuffer.error, |
| HasSubstr("Failed to execute 'postMessage' on 'Window':")); |
| } |
| |
| // Transfer a SharedArrayBuffer in between two COOP+COEP document with a |
| // parent/child relationship. The child has set Permissions-Policy: |
| // cross-origin-isolated=(). This non-cross-origin-isolated document can |
| // transfer a SharedArrayBuffer toward the cross-origin-isolated one. |
| // See https://crbug.com/1144838 for discussions about this behavior. |
| IN_PROC_BROWSER_TEST_P( |
| NoSharedArrayBufferByDefault, |
| CoopCoepTransferSharedArrayBufferFromNoCrossOriginIsolatedIframe) { |
| CHECK(!base::FeatureList::IsEnabled(features::kSharedArrayBuffer)); |
| GURL main_url = |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin&" |
| "Cross-Origin-Embedder-Policy: require-corp"); |
| GURL iframe_url = |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Embedder-Policy: require-corp&" |
| "Cross-Origin-Resource-Policy: cross-origin&" |
| "Permissions-Policy: cross-origin-isolated%3D()"); |
| EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| EXPECT_TRUE(ExecJs(current_frame_host(), |
| JsReplace("g_iframe = document.createElement('iframe');" |
| "g_iframe.src = $1;" |
| "document.body.appendChild(g_iframe);", |
| iframe_url))); |
| WaitForLoadStop(web_contents()); |
| |
| RenderFrameHostImpl* main_document = current_frame_host(); |
| RenderFrameHostImpl* sub_document = |
| current_frame_host()->child_at(0)->current_frame_host(); |
| |
| EXPECT_EQ(true, EvalJs(main_document, "self.crossOriginIsolated")); |
| EXPECT_EQ(false, EvalJs(sub_document, "self.crossOriginIsolated")); |
| |
| EXPECT_TRUE(ExecJs(main_document, R"( |
| g_sab_size = new Promise(resolve => { |
| addEventListener("message", event => resolve(event.data.byteLength)); |
| }); |
| )", |
| EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); |
| |
| EXPECT_EQ(false, EvalJs(sub_document, "'SharedArrayBuffer' in globalThis")); |
| |
| // TODO(https://crbug.com/1144838): Being able to share SharedArrayBuffer from |
| // a document with self.crossOriginIsolated == false sounds wrong. |
| EXPECT_TRUE(ExecJs(sub_document, R"( |
| // Create a WebAssembly Memory to bypass the SAB constructor restriction. |
| const sab = new (new WebAssembly.Memory( |
| { shared:true, initial:1, maximum:1 }).buffer.constructor)(1234); |
| parent.postMessage(sab, "*"); |
| )")); |
| |
| EXPECT_EQ(1234, EvalJs(main_document, "g_sab_size")); |
| } |
| |
| // Ensure the UnrestrictedSharedArrayBuffer reverse origin trial is correctly |
| // implemented. |
| class UnrestrictedSharedArrayBufferOriginTrialBrowserTest |
| : public ContentBrowserTest { |
| public: |
| UnrestrictedSharedArrayBufferOriginTrialBrowserTest() { |
| feature_list_.InitWithFeatures( |
| { |
| // Enabled |
| }, |
| { |
| // Disabled |
| features::kSharedArrayBuffer, |
| }); |
| } |
| |
| // Origin Trials key generated with: |
| // |
| // tools/origin_trials/generate_token.py --expire-days 5000 --version 3 |
| // https://coop.security:9999 UnrestrictedSharedArrayBuffer |
| static std::string OriginTrialToken() { |
| return "A8TH8Ylk6lUuL84RdQ2+FTyupad3leg5sMk+MYEoVlwkURyBtVq1IFncJAc2k" |
| "Knhh5w3SvIR4XuEtyMzeI2u4wAAAABqeyJvcmlnaW4iOiAiaHR0cHM6Ly9jb2" |
| "9wLnNlY3VyaXR5Ojk5OTkiLCAiZmVhdHVyZSI6ICJVbnJlc3RyaWN0ZWRTaGF" |
| "yZWRBcnJheUJ1ZmZlciIsICJleHBpcnkiOiAyMDQ1Njk0NDMyfQ=="; |
| } |
| |
| // The OriginTrial token is bound to a given origin. Since the |
| // EmbeddedTestServer's port changes after every test run, it can't be used. |
| // As a result, response must be served using a URLLoaderInterceptor. |
| GURL OriginTrialURL() { return GURL("https://coop.security:9999"); } |
| |
| WebContentsImpl* web_contents() const { |
| return static_cast<WebContentsImpl*>(shell()->web_contents()); |
| } |
| |
| RenderFrameHostImpl* current_frame_host() { |
| return web_contents()->GetMainFrame(); |
| } |
| |
| net::EmbeddedTestServer* https_server() { return &https_server_; } |
| |
| private: |
| void SetUpOnMainThread() override { |
| ContentBrowserTest::SetUpOnMainThread(); |
| mock_cert_verifier_.mock_cert_verifier()->set_default_result(net::OK); |
| host_resolver()->AddRule("*", "127.0.0.1"); |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| https_server()->ServeFilesFromSourceDirectory(GetTestDataFilePath()); |
| SetupCrossSiteRedirector(https_server()); |
| net::test_server::RegisterDefaultHandlers(&https_server_); |
| ASSERT_TRUE(https_server()->Start()); |
| } |
| |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| ContentBrowserTest::SetUpCommandLine(command_line); |
| mock_cert_verifier_.SetUpCommandLine(command_line); |
| } |
| |
| void SetUpInProcessBrowserTestFixture() override { |
| ContentBrowserTest::SetUpInProcessBrowserTestFixture(); |
| mock_cert_verifier_.SetUpInProcessBrowserTestFixture(); |
| } |
| |
| void TearDownInProcessBrowserTestFixture() override { |
| ContentBrowserTest::TearDownInProcessBrowserTestFixture(); |
| mock_cert_verifier_.TearDownInProcessBrowserTestFixture(); |
| } |
| |
| content::ContentMockCertVerifier mock_cert_verifier_; |
| base::test::ScopedFeatureList feature_list_; |
| net::EmbeddedTestServer https_server_; |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(UnrestrictedSharedArrayBufferOriginTrialBrowserTest, |
| HasSharedArrayBuffer) { |
| URLLoaderInterceptor interceptor(base::BindLambdaForTesting( |
| [&](URLLoaderInterceptor::RequestParams* params) { |
| DCHECK_EQ(params->url_request.url, OriginTrialURL()); |
| URLLoaderInterceptor::WriteResponse( |
| "HTTP/1.1 200 OK\n" |
| "Content-type: text/html\n" |
| "Origin-Trial: " + |
| OriginTrialToken() + "\n\n", |
| "", params->client.get()); |
| return true; |
| })); |
| EXPECT_TRUE(NavigateToURL(shell(), OriginTrialURL())); |
| |
| EXPECT_EQ(false, EvalJs(current_frame_host(), "self.crossOriginIsolated")); |
| #if !BUILDFLAG(IS_ANDROID) |
| EXPECT_EQ(true, |
| EvalJs(current_frame_host(), "'SharedArrayBuffer' in globalThis")); |
| #else // !BUILDFLAG(IS_ANDROID) |
| EXPECT_EQ(false, |
| EvalJs(current_frame_host(), "'SharedArrayBuffer' in globalThis")); |
| #endif // !BUILDFLAG(IS_ANDROID) |
| } |
| |
| // Check setting the OriginTrial works, even in popups where the javascript |
| // context of the initial empty document is reused. |
| IN_PROC_BROWSER_TEST_F(UnrestrictedSharedArrayBufferOriginTrialBrowserTest, |
| HasSharedArrayBufferReuseContext) { |
| // Create a document without the origin trial in a renderer process. |
| { |
| URLLoaderInterceptor interceptor(base::BindLambdaForTesting( |
| [&](URLLoaderInterceptor::RequestParams* params) { |
| DCHECK_EQ(params->url_request.url, OriginTrialURL()); |
| URLLoaderInterceptor::WriteResponse( |
| "HTTP/1.1 200 OK\n" |
| "Content-type: text/html\n\n", |
| "", params->client.get()); |
| return true; |
| })); |
| EXPECT_TRUE(NavigateToURL(shell(), OriginTrialURL())); |
| EXPECT_EQ(false, EvalJs(current_frame_host(), |
| "'SharedArrayBuffer' in globalThis")); |
| } |
| |
| // In the same process, open a popup. The document loaded defines an |
| // OriginTrial. It will reuse the javascript context created for the initial |
| // empty document. |
| { |
| URLLoaderInterceptor interceptor(base::BindLambdaForTesting( |
| [&](URLLoaderInterceptor::RequestParams* params) { |
| DCHECK_EQ(params->url_request.url, OriginTrialURL()); |
| URLLoaderInterceptor::WriteResponse( |
| "HTTP/1.1 200 OK\n" |
| "Content-type: text/html\n" |
| "Origin-Trial: " + |
| OriginTrialToken() + "\n\n", |
| "", params->client.get()); |
| return true; |
| })); |
| ShellAddedObserver shell_observer; |
| EXPECT_TRUE(ExecJs(current_frame_host(), "window.open(location.href)")); |
| |
| auto* popup = static_cast<WebContentsImpl*>( |
| shell_observer.GetShell()->web_contents()); |
| WaitForLoadStop(popup); |
| |
| #if BUILDFLAG(IS_ANDROID) |
| EXPECT_EQ(false, EvalJs(popup, "'SharedArrayBuffer' in globalThis")); |
| #else |
| EXPECT_EQ(true, EvalJs(popup, "'SharedArrayBuffer' in globalThis")); |
| #endif |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_F(UnrestrictedSharedArrayBufferOriginTrialBrowserTest, |
| SupportForMeta) { |
| URLLoaderInterceptor interceptor(base::BindLambdaForTesting( |
| [&](URLLoaderInterceptor::RequestParams* params) { |
| DCHECK_EQ(params->url_request.url, OriginTrialURL()); |
| URLLoaderInterceptor::WriteResponse( |
| "HTTP/1.1 200 OK\n" |
| "Content-type: text/html\n", |
| "<meta http-equiv=\"origin-trial\" content=\"" + |
| OriginTrialToken() + "\">", |
| params->client.get()); |
| return true; |
| })); |
| EXPECT_TRUE(NavigateToURL(shell(), OriginTrialURL())); |
| |
| EXPECT_EQ(false, EvalJs(current_frame_host(), "self.crossOriginIsolated")); |
| |
| #if BUILDFLAG(IS_ANDROID) |
| EXPECT_EQ(false, |
| EvalJs(current_frame_host(), "'SharedArrayBuffer' in globalThis")); |
| #else |
| EXPECT_EQ(true, |
| EvalJs(current_frame_host(), "'SharedArrayBuffer' in globalThis")); |
| #endif |
| } |
| |
| IN_PROC_BROWSER_TEST_F(UnrestrictedSharedArrayBufferOriginTrialBrowserTest, |
| TransferSharedArrayBuffer) { |
| URLLoaderInterceptor interceptor(base::BindLambdaForTesting( |
| [&](URLLoaderInterceptor::RequestParams* params) { |
| DCHECK_EQ(params->url_request.url, OriginTrialURL()); |
| URLLoaderInterceptor::WriteResponse( |
| "HTTP/1.1 200 OK\n" |
| "Content-type: text/html\n" |
| "Origin-Trial: " + |
| OriginTrialToken() + "\n\n", |
| "", params->client.get()); |
| return true; |
| })); |
| EXPECT_TRUE(NavigateToURL(shell(), OriginTrialURL())); |
| |
| EXPECT_TRUE(ExecJs(current_frame_host(), |
| "g_iframe = document.createElement('iframe');" |
| "g_iframe.src = location.href;" |
| "document.body.appendChild(g_iframe);")); |
| WaitForLoadStop(web_contents()); |
| |
| RenderFrameHostImpl* main_document = current_frame_host(); |
| RenderFrameHostImpl* sub_document = |
| current_frame_host()->child_at(0)->current_frame_host(); |
| |
| EXPECT_EQ(false, EvalJs(main_document, "self.crossOriginIsolated")); |
| EXPECT_EQ(false, EvalJs(sub_document, "self.crossOriginIsolated")); |
| |
| #if !BUILDFLAG(IS_ANDROID) |
| EXPECT_TRUE(ExecJs(sub_document, R"( |
| g_sab_size = new Promise(resolve => { |
| addEventListener("message", event => resolve(event.data.byteLength)); |
| }); |
| )", |
| EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); |
| |
| EXPECT_TRUE(ExecJs(main_document, R"( |
| const sab = new SharedArrayBuffer(1234); |
| g_iframe.contentWindow.postMessage(sab, "*"); |
| )")); |
| |
| EXPECT_EQ(1234, EvalJs(sub_document, "g_sab_size")); |
| #else // !BUILDFLAG(IS_ANDROID) |
| auto postSharedArrayBuffer = EvalJs(main_document, R"( |
| // Create a WebAssembly Memory to bypass the SAB constructor restriction. |
| const sab = |
| new WebAssembly.Memory({ shared:true, initial:1, maximum:1 }).buffer; |
| g_iframe.contentWindow.postMessage(sab,"*"); |
| )"); |
| |
| EXPECT_THAT(postSharedArrayBuffer.error, |
| HasSubstr("Failed to execute 'postMessage' on 'Window'")); |
| #endif // !BUILDFLAG(IS_ANDROID) |
| } |
| |
| // Enable the reverse OriginTrial via a <meta> tag. Then send a Webassembly's |
| // SharedArrayBuffer toward the iframe. |
| // Regression test for https://crbug.com/1201589). |
| // The SAB reverse origin trial only work on Desktop. |
| #if !BUILDFLAG(IS_ANDROID) |
| IN_PROC_BROWSER_TEST_F(UnrestrictedSharedArrayBufferOriginTrialBrowserTest, |
| CrashForBug1201589) { |
| URLLoaderInterceptor interceptor(base::BindLambdaForTesting( |
| [&](URLLoaderInterceptor::RequestParams* params) { |
| DCHECK_EQ(params->url_request.url, OriginTrialURL()); |
| URLLoaderInterceptor::WriteResponse( |
| "HTTP/1.1 200 OK\n" |
| "Content-type: text/html\n", |
| "<meta http-equiv=\"origin-trial\" content=\"" + |
| OriginTrialToken() + "\">", |
| params->client.get()); |
| return true; |
| })); |
| EXPECT_TRUE(NavigateToURL(shell(), OriginTrialURL())); |
| |
| EXPECT_TRUE(ExecJs(current_frame_host(), |
| "g_iframe = document.createElement('iframe');" |
| "g_iframe.src = location.href;" |
| "document.body.appendChild(g_iframe);")); |
| WaitForLoadStop(web_contents()); |
| |
| RenderFrameHostImpl* main_document = current_frame_host(); |
| RenderFrameHostImpl* sub_document = |
| current_frame_host()->child_at(0)->current_frame_host(); |
| |
| EXPECT_EQ(false, EvalJs(main_document, "self.crossOriginIsolated")); |
| EXPECT_EQ(false, EvalJs(sub_document, "self.crossOriginIsolated")); |
| |
| EXPECT_EQ(true, EvalJs(main_document, "'SharedArrayBuffer' in globalThis")); |
| EXPECT_EQ(true, EvalJs(sub_document, "'SharedArrayBuffer' in globalThis")); |
| |
| EXPECT_TRUE(ExecJs(sub_document, R"( |
| g_sab_size = new Promise(resolve => { |
| addEventListener("message", event => resolve(event.data.byteLength)); |
| }); |
| )", |
| EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); |
| |
| EXPECT_TRUE(ExecJs(main_document, R"( |
| const wasm_shared_memory = new WebAssembly.Memory({ |
| shared:true, initial:0, maximum:0 }); |
| g_iframe.contentWindow.postMessage(wasm_shared_memory.buffer, "*"); |
| )")); |
| EXPECT_EQ(0, EvalJs(sub_document, "g_sab_size")); |
| } |
| #endif |
| |
| // Ensure the SharedArrayBufferOnDesktop kill switch is correctly implemented. |
| class SharedArrayBufferOnDesktopBrowserTest |
| : public CrossOriginOpenerPolicyBrowserTest { |
| public: |
| SharedArrayBufferOnDesktopBrowserTest() { |
| feature_list_.InitWithFeatures( |
| { |
| // Enabled |
| features::kSharedArrayBufferOnDesktop, |
| }, |
| { |
| // Disabled |
| features::kSharedArrayBuffer, |
| }); |
| } |
| |
| private: |
| base::test::ScopedFeatureList feature_list_; |
| }; |
| |
| INSTANTIATE_TEST_SUITE_P(All, |
| SharedArrayBufferOnDesktopBrowserTest, |
| kTestParams, |
| CrossOriginOpenerPolicyBrowserTest::DescribeParams); |
| |
| IN_PROC_BROWSER_TEST_P(SharedArrayBufferOnDesktopBrowserTest, |
| DesktopHasSharedArrayBuffer) { |
| CHECK(!base::FeatureList::IsEnabled(features::kSharedArrayBuffer)); |
| GURL url = https_server()->GetURL("a.test", "/empty.html"); |
| EXPECT_TRUE(NavigateToURL(shell(), url)); |
| EXPECT_EQ(false, EvalJs(current_frame_host(), "self.crossOriginIsolated")); |
| #if !BUILDFLAG(IS_ANDROID) |
| EXPECT_EQ(true, |
| EvalJs(current_frame_host(), "'SharedArrayBuffer' in globalThis")); |
| #else // !BUILDFLAG(IS_ANDROID) |
| EXPECT_EQ(false, |
| EvalJs(current_frame_host(), "'SharedArrayBuffer' in globalThis")); |
| #endif // !BUILDFLAG(IS_ANDROID) |
| } |
| |
| IN_PROC_BROWSER_TEST_P(SharedArrayBufferOnDesktopBrowserTest, |
| DesktopTransferSharedArrayBuffer) { |
| CHECK(!base::FeatureList::IsEnabled(features::kSharedArrayBuffer)); |
| GURL main_url = https_server()->GetURL("a.test", "/empty.html"); |
| GURL iframe_url = https_server()->GetURL("a.test", "/empty.html"); |
| EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| EXPECT_TRUE(ExecJs(current_frame_host(), |
| JsReplace("g_iframe = document.createElement('iframe');" |
| "g_iframe.src = $1;" |
| "document.body.appendChild(g_iframe);", |
| iframe_url))); |
| WaitForLoadStop(web_contents()); |
| |
| RenderFrameHostImpl* main_document = current_frame_host(); |
| RenderFrameHostImpl* sub_document = |
| current_frame_host()->child_at(0)->current_frame_host(); |
| |
| EXPECT_EQ(false, EvalJs(main_document, "self.crossOriginIsolated")); |
| EXPECT_EQ(false, EvalJs(sub_document, "self.crossOriginIsolated")); |
| |
| EXPECT_TRUE(ExecJs(main_document, R"( |
| g_sab_size = new Promise(resolve => { |
| addEventListener("message", event => resolve(event.data.byteLength)); |
| }); |
| )", |
| EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); |
| |
| #if !BUILDFLAG(IS_ANDROID) |
| EXPECT_TRUE(ExecJs(sub_document, R"( |
| const sab = new SharedArrayBuffer(1234); |
| parent.postMessage(sab, "*"); |
| )")); |
| |
| EXPECT_EQ(1234, EvalJs(main_document, "g_sab_size")); |
| #else // !BUILDFLAG(IS_ANDROID) |
| EXPECT_FALSE(ExecJs(sub_document, R"( |
| const sab = new SharedArrayBuffer(1234); |
| parent.postMessage(sab, "*"); |
| )")); |
| #endif // !BUILDFLAG(IS_ANDROID) |
| } |
| |
| IN_PROC_BROWSER_TEST_P(SoapByDefaultVirtualBrowsingContextGroupTest, NoHeader) { |
| const VirtualBcgAllowPopupTestCase kTestCases[] = { |
| { |
| // same-origin. |
| https_server()->GetURL("a.test", "/title1.html"), |
| https_server()->GetURL("a.test", "/title1.html"), |
| false, |
| false, |
| SoapByDefaultVirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-origin. |
| https_server()->GetURL("a.a.test", "/title1.html"), |
| https_server()->GetURL("b.a.test", "/title1.html"), |
| true, |
| true, |
| SoapByDefaultVirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-site. |
| https_server()->GetURL("a.test", "/title1.html"), |
| https_server()->GetURL("b.test", "/title1.html"), |
| true, |
| true, |
| SoapByDefaultVirtualBrowsingContextGroup, |
| }, |
| }; |
| for (const auto& test : kTestCases) |
| RunTest(test, shell()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(SoapByDefaultVirtualBrowsingContextGroupTest, |
| ToUnsafeNone) { |
| const VirtualBcgAllowPopupTestCase kTestCases[] = { |
| { |
| // same-origin. |
| https_server()->GetURL("a.test", "/title1.html"), |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: unsafe-none"), |
| false, |
| true, |
| SoapByDefaultVirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-origin. |
| https_server()->GetURL("a.a.test", "/title1.html"), |
| https_server()->GetURL("b.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: unsafe-none"), |
| false, |
| true, |
| SoapByDefaultVirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-site. |
| https_server()->GetURL("a.test", "/title1.html"), |
| https_server()->GetURL("b.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: unsafe-none"), |
| false, |
| true, |
| SoapByDefaultVirtualBrowsingContextGroup, |
| }, |
| }; |
| for (const auto& test : kTestCases) |
| RunTest(test, shell()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(SoapByDefaultVirtualBrowsingContextGroupTest, |
| FromUnsafeNone) { |
| const VirtualBcgAllowPopupTestCase kTestCases[] = { |
| { |
| // same-origin. |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: unsafe-none"), |
| https_server()->GetURL("a.test", "/title1.html"), |
| true, |
| true, |
| SoapByDefaultVirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-origin. |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: unsafe-none"), |
| https_server()->GetURL("b.a.test", "/title1.html"), |
| true, |
| true, |
| SoapByDefaultVirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-site. |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: unsafe-none"), |
| https_server()->GetURL("b.test", "/title1.html"), |
| true, |
| true, |
| SoapByDefaultVirtualBrowsingContextGroup, |
| }, |
| }; |
| for (const auto& test : kTestCases) |
| RunTest(test, shell()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(SoapByDefaultVirtualBrowsingContextGroupTest, |
| ToSameOriginAllowPopups) { |
| const VirtualBcgAllowPopupTestCase kTestCases[] = { |
| { |
| // same-origin. |
| https_server()->GetURL("a.test", "/title1.html"), |
| https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups"), |
| false, |
| false, |
| SoapByDefaultVirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-origin. |
| https_server()->GetURL("a.a.test", "/title1.html"), |
| https_server()->GetURL( |
| "b.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups"), |
| true, |
| true, |
| SoapByDefaultVirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-site. |
| https_server()->GetURL("a.test", "/title1.html"), |
| https_server()->GetURL( |
| "b.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups"), |
| true, |
| true, |
| SoapByDefaultVirtualBrowsingContextGroup, |
| }, |
| }; |
| for (const auto& test : kTestCases) |
| RunTest(test, shell()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(SoapByDefaultVirtualBrowsingContextGroupTest, |
| FromSameOriginAllowPopus) { |
| const VirtualBcgAllowPopupTestCase kTestCases[] = { |
| { |
| // same-origin. |
| https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups"), |
| https_server()->GetURL("a.test", "/title1.html"), |
| false, |
| false, |
| SoapByDefaultVirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-origin. |
| https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups"), |
| https_server()->GetURL("b.a.test", "/title1.html"), |
| true, |
| true, |
| SoapByDefaultVirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-site. |
| https_server()->GetURL( |
| "a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin-allow-popups"), |
| https_server()->GetURL("b.test", "/title1.html"), |
| true, |
| true, |
| SoapByDefaultVirtualBrowsingContextGroup, |
| }, |
| }; |
| for (const auto& test : kTestCases) |
| RunTest(test, shell()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(SoapByDefaultVirtualBrowsingContextGroupTest, |
| ToSameOrigin) { |
| const VirtualBcgAllowPopupTestCase kTestCases[] = { |
| { |
| // same-origin. |
| https_server()->GetURL("a.test", "/title1.html"), |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin"), |
| true, |
| true, |
| SoapByDefaultVirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-origin. |
| https_server()->GetURL("a.a.test", "/title1.html"), |
| https_server()->GetURL("b.a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin"), |
| true, |
| true, |
| SoapByDefaultVirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-site. |
| https_server()->GetURL("a.test", "/title1.html"), |
| https_server()->GetURL("b.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin"), |
| true, |
| true, |
| SoapByDefaultVirtualBrowsingContextGroup, |
| }, |
| }; |
| for (const auto& test : kTestCases) |
| RunTest(test, shell()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(SoapByDefaultVirtualBrowsingContextGroupTest, |
| FromSameOrigin) { |
| const VirtualBcgAllowPopupTestCase kTestCases[] = { |
| { |
| // same-origin. |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin"), |
| https_server()->GetURL("a.test", "/title1.html"), |
| true, |
| true, |
| SoapByDefaultVirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-origin. |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin"), |
| https_server()->GetURL("b.a.test", "/title1.html"), |
| true, |
| true, |
| SoapByDefaultVirtualBrowsingContextGroup, |
| }, |
| { |
| // cross-site. |
| https_server()->GetURL("a.test", |
| "/set-header?" |
| "Cross-Origin-Opener-Policy: same-origin"), |
| https_server()->GetURL("b.test", "/title1.html"), |
| true, |
| true, |
| SoapByDefaultVirtualBrowsingContextGroup, |
| }, |
| }; |
| for (const auto& test : kTestCases) |
| RunTest(test, shell()); |
| } |
| |
| // Navigates in between two pages from a different browsing context group. Then |
| // use the history API to navigate back and forth. Check their virtual browsing |
| // context group isn't restored. |
| // The goal is to spot differences when the BackForwardCache is enabled. See |
| // https://crbug.com/1109648. |
| IN_PROC_BROWSER_TEST_P(SoapByDefaultVirtualBrowsingContextGroupTest, |
| HistoryNavigation) { |
| GURL url_a = https_server()->GetURL("a.test", "/title1.html"); |
| GURL url_b = https_server()->GetURL("b.test", "/title1.html"); |
| |
| EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
| int group_1 = SoapByDefaultVirtualBrowsingContextGroup(web_contents()); |
| |
| EXPECT_TRUE(NavigateToURL(shell(), url_b)); |
| int group_2 = SoapByDefaultVirtualBrowsingContextGroup(web_contents()); |
| |
| web_contents()->GetController().GoBack(); |
| EXPECT_TRUE(WaitForLoadStop(web_contents())); |
| int group_3 = SoapByDefaultVirtualBrowsingContextGroup(web_contents()); |
| |
| web_contents()->GetController().GoForward(); |
| EXPECT_TRUE(WaitForLoadStop(web_contents())); |
| int group_4 = SoapByDefaultVirtualBrowsingContextGroup(web_contents()); |
| |
| // No matter whether the BackForwardCache is enabled or not, the navigation in |
| // between the two URLs must always cross a virtual browsing context group. |
| EXPECT_NE(group_1, group_2); |
| EXPECT_NE(group_2, group_3); |
| EXPECT_NE(group_3, group_4); |
| EXPECT_NE(group_1, group_4); |
| |
| // TODO(https://crbug.com/1112256) During history navigation, the virtual |
| // browsing context group must be restored whenever the SiteInstance is |
| // restored. Currently, the SiteInstance is restored, but the virtual browsing |
| // context group is new. |
| |
| if (IsBackForwardCacheEnabled()) { |
| EXPECT_EQ(group_1, group_3); |
| EXPECT_EQ(group_2, group_4); |
| } else { |
| EXPECT_NE(group_1, group_3); |
| EXPECT_NE(group_2, group_4); |
| } |
| } |
| |
| // 1. A1 opens A2 (same virtual browsing context group). |
| // 2. A2 navigates to B3 (different virtual browsing context group). |
| // 3. B3 navigates back to A4 using the history (different virtual browsing |
| // context group). |
| // |
| // A1 and A4 must not be in the same browsing context group. |
| IN_PROC_BROWSER_TEST_P(SoapByDefaultVirtualBrowsingContextGroupTest, |
| HistoryNavigationWithPopup) { |
| GURL url_a = https_server()->GetURL("a.test", "/title1.html"); |
| GURL url_b = https_server()->GetURL("b.test", "/title1.html"); |
| |
| // Navigate to A1. |
| EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
| int group_1 = SoapByDefaultVirtualBrowsingContextGroup(web_contents()); |
| |
| // A1 opens A2. |
| ShellAddedObserver shell_observer; |
| EXPECT_TRUE( |
| ExecJs(current_frame_host(), JsReplace("window.open($1)", url_a))); |
| WebContents* popup = shell_observer.GetShell()->web_contents(); |
| EXPECT_TRUE(WaitForLoadStop(popup)); |
| int group_2 = SoapByDefaultVirtualBrowsingContextGroup(popup); |
| |
| // A2 navigates to B3. |
| EXPECT_TRUE(ExecJs(popup, JsReplace("location.href = $1;", url_b))); |
| EXPECT_TRUE(WaitForLoadStop(popup)); |
| int group_3 = SoapByDefaultVirtualBrowsingContextGroup(popup); |
| |
| // B3 navigates back to A4. |
| EXPECT_TRUE(ExecJs(popup, JsReplace("history.back()"))); |
| EXPECT_TRUE(WaitForLoadStop(popup)); |
| int group_4 = SoapByDefaultVirtualBrowsingContextGroup(popup); |
| |
| EXPECT_EQ(group_1, group_2); |
| EXPECT_NE(group_2, group_3); |
| EXPECT_NE(group_3, group_4); |
| EXPECT_NE(group_4, group_1); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(SameOriginAllowPopupsPlusCoepBrowserTest, |
| CoopSameOriginAllowPopupsPlusCoepIsParsed) { |
| GURL starting_page(https_server()->GetURL( |
| "a.test", |
| "/set-header" |
| "?cross-origin-opener-policy: same-origin-allow-popups" |
| "&cross-origin-embedder-policy: require-corp")); |
| EXPECT_TRUE(NavigateToURL(shell(), starting_page)); |
| |
| // Verify that COOP:SOAPPC was parsed, and that it correctly enabled cross |
| // origin isolation. |
| EXPECT_EQ(current_frame_host()->cross_origin_opener_policy(), |
| CoopSameOriginAllowPopupsPlusCoep()); |
| EXPECT_TRUE(current_frame_host()->GetSiteInstance()->IsCrossOriginIsolated()); |
| } |
| |
| IN_PROC_BROWSER_TEST_P(NoSiteIsolationCrossOriginIsolationBrowserTest, |
| COICanLiveInDefaultSI) { |
| GURL isolated_page( |
| https_server()->GetURL("a.test", |
| "/set-header" |
| "?cross-origin-opener-policy: same-origin" |
| "&cross-origin-embedder-policy: require-corp")); |
| GURL non_isolated_page(https_server()->GetURL("a.test", "/title1.html")); |
| |
| EXPECT_TRUE(NavigateToURL(shell(), isolated_page)); |
| SiteInstanceImpl* main_frame_si = current_frame_host()->GetSiteInstance(); |
| EXPECT_TRUE(main_frame_si->IsCrossOriginIsolated()); |
| EXPECT_TRUE(main_frame_si->IsDefaultSiteInstance()); |
| |
| { |
| // Open a popup to a page with similar isolation. Pages that have compatible |
| // cross origin isolation should be put in the same default SiteInstance. |
| ShellAddedObserver shell_observer; |
| EXPECT_TRUE(ExecJs(current_frame_host(), |
| JsReplace("window.open($1);", isolated_page))); |
| WebContentsImpl* popup = static_cast<WebContentsImpl*>( |
| shell_observer.GetShell()->web_contents()); |
| EXPECT_TRUE(WaitForLoadStop(popup)); |
| |
| SiteInstanceImpl* popup_si = popup->GetMainFrame()->GetSiteInstance(); |
| EXPECT_TRUE(popup_si->IsCrossOriginIsolated()); |
| EXPECT_TRUE(popup_si->IsDefaultSiteInstance()); |
| EXPECT_EQ(popup_si, main_frame_si); |
| |
| popup->Close(); |
| } |
| |
| { |
| // Open a popup to a same origin non-isolated page. This page should live in |
| // a different BrowsingInstance in the default non-isolated SiteInstance. |
| ShellAddedObserver shell_observer; |
| EXPECT_TRUE(ExecJs(current_frame_host(), |
| JsReplace("window.open($1);", non_isolated_page))); |
| WebContentsImpl* popup = static_cast<WebContentsImpl*>( |
| shell_observer.GetShell()->web_contents()); |
| EXPECT_TRUE(WaitForLoadStop(popup)); |
| |
| SiteInstanceImpl* popup_si = popup->GetMainFrame()->GetSiteInstance(); |
| EXPECT_FALSE(popup_si->IsCrossOriginIsolated()); |
| EXPECT_TRUE(popup_si->IsDefaultSiteInstance()); |
| EXPECT_NE(popup_si, main_frame_si); |
| |
| popup->Close(); |
| } |
| } |
| |
| } // namespace content |