diff --git a/content/browser/cross_origin_opener_policy_browsertest.cc b/content/browser/cross_origin_opener_policy_browsertest.cc index 334f1013bcccf1..dceab9fca9be37 100644 --- a/content/browser/cross_origin_opener_policy_browsertest.cc +++ b/content/browser/cross_origin_opener_policy_browsertest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/test/scoped_feature_list.h" +#include "content/browser/frame_host/navigation_request.h" #include "content/browser/frame_host/render_frame_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/test/content_browser_test.h" @@ -200,4 +201,58 @@ IN_PROC_BROWSER_TEST_F(CrossOriginOpenerPolicyBrowserTest, web_contents()->GetController().GetLastCommittedEntry()->GetPageType(), PAGE_TYPE_NORMAL); } + +class CrossOriginPolicyHeadersObserver : public WebContentsObserver { + public: + explicit CrossOriginPolicyHeadersObserver( + WebContents* web_contents, + network::mojom::CrossOriginEmbedderPolicyValue expected_coep, + network::mojom::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(navigation_handle); + CHECK(navigation_request->response()->cross_origin_embedder_policy.value == + expected_coep_); + CHECK(navigation_request->response()->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(navigation_handle); + CHECK(navigation_request->response()->cross_origin_embedder_policy.value == + expected_coep_); + CHECK(navigation_request->response()->cross_origin_opener_policy == + expected_coop_); + } + + private: + network::mojom::CrossOriginEmbedderPolicyValue expected_coep_; + network::mojom::CrossOriginOpenerPolicy expected_coop_; +}; + +IN_PROC_BROWSER_TEST_F(CrossOriginOpenerPolicyBrowserTest, + RedirectsParseCoopAndCoepHeaders) { + GURL redirect_initial_page(embedded_test_server()->GetURL( + "a.com", "/cross-origin-opener-policy_redirect_initial.html")); + GURL redirect_final_page(embedded_test_server()->GetURL( + "a.com", "/cross-origin-opener-policy_redirect_final.html")); + + CrossOriginPolicyHeadersObserver obs( + web_contents(), + network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp, + network::mojom::CrossOriginOpenerPolicy::kSameOrigin); + + EXPECT_TRUE( + NavigateToURL(shell(), redirect_initial_page, redirect_final_page)); +} + } // namespace content diff --git a/content/test/data/cross-origin-opener-policy_redirect_final.html b/content/test/data/cross-origin-opener-policy_redirect_final.html new file mode 100644 index 00000000000000..7930bc57255d0c --- /dev/null +++ b/content/test/data/cross-origin-opener-policy_redirect_final.html @@ -0,0 +1 @@ +Document with "Cross-Origin-Opener-Policy: same-origin" diff --git a/content/test/data/cross-origin-opener-policy_redirect_final.html.mock-http-headers b/content/test/data/cross-origin-opener-policy_redirect_final.html.mock-http-headers new file mode 100644 index 00000000000000..858d4a51035fe2 --- /dev/null +++ b/content/test/data/cross-origin-opener-policy_redirect_final.html.mock-http-headers @@ -0,0 +1,4 @@ +HTTP/1.1 200 OK +Content-Type: text/html +Cross-Origin-Opener-Policy: same-origin +Cross-Origin-Embedder-Policy: require-corp diff --git a/content/test/data/cross-origin-opener-policy_redirect_initial.html b/content/test/data/cross-origin-opener-policy_redirect_initial.html new file mode 100644 index 00000000000000..7930bc57255d0c --- /dev/null +++ b/content/test/data/cross-origin-opener-policy_redirect_initial.html @@ -0,0 +1 @@ +Document with "Cross-Origin-Opener-Policy: same-origin" diff --git a/content/test/data/cross-origin-opener-policy_redirect_initial.html.mock-http-headers b/content/test/data/cross-origin-opener-policy_redirect_initial.html.mock-http-headers new file mode 100644 index 00000000000000..a95119f80ffd08 --- /dev/null +++ b/content/test/data/cross-origin-opener-policy_redirect_initial.html.mock-http-headers @@ -0,0 +1,4 @@ +HTTP/1.1 301 Moved Permanently +Location: cross-origin-opener-policy_redirect_final.html +Cross-Origin-Opener-Policy: same-origin +Cross-Origin-Embedder-Policy: require-corp diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc index 3f1e599fd34284..eeec0c9abcbadd 100644 --- a/services/network/url_loader.cc +++ b/services/network/url_loader.cc @@ -122,6 +122,26 @@ void PopulateResourceResponse(net::URLRequest* request, response->ssl_info = request->ssl_info(); } + // TODO(ahemery): Cross origin isolation headers should only be parsed for + // secure contexts. Check here using IsUrlPotentiallyTrustworthy() once the + // tests are updated to use HTTPS. + if (base::FeatureList::IsEnabled(features::kCrossOriginIsolation)) { + // Parse the Cross-Origin-Embedder-Policy and + // Cross-Origin-Embedder-Policy-Report-Only headers. + response->cross_origin_embedder_policy = + URLLoader::ParseCrossOriginEmbedderPolicyValue( + request->response_headers()); + + // Parse the Cross-Origin-Opener-Policy header. + std::string raw_coop_string; + if (request->response_headers() && + request->response_headers()->GetNormalizedHeader( + kCrossOriginOpenerPolicyHeader, &raw_coop_string)) { + response->cross_origin_opener_policy = + ParseCrossOriginOpenerPolicyHeader(raw_coop_string); + } + } + response->request_start = request->creation_time(); response->response_start = base::TimeTicks::Now(); response->encoded_data_length = request->GetTotalReceivedBytes(); @@ -1153,22 +1173,6 @@ void URLLoader::OnResponseStarted(net::URLRequest* url_request, int net_error) { &(response_->content_security_policy)); } - if (base::FeatureList::IsEnabled(features::kCrossOriginIsolation)) { - // Parse the Cross-Origin-Embedder-Policy and - // Cross-Origin-Embedder-Policy-Report-Only headers. - response_->cross_origin_embedder_policy = - ParseCrossOriginEmbedderPolicyValue(url_request_->response_headers()); - - // Parse the Cross-Origin-Opener-Policy header. - std::string raw_coop_string; - if (url_request_->response_headers() && - url_request_->response_headers()->GetNormalizedHeader( - kCrossOriginOpenerPolicyHeader, &raw_coop_string)) { - response_->cross_origin_opener_policy = - ParseCrossOriginOpenerPolicyHeader(raw_coop_string); - } - } - // If necessary, retrieve the associated origin policy, before sending the // response to the client. if (origin_policy_manager_ && url_request_->response_headers()) {