diff --git a/content/browser/service_worker/service_worker_navigation_loader_unittest.cc b/content/browser/service_worker/service_worker_navigation_loader_unittest.cc index 1ababc7553669b..e1f3d1d2d65244 100644 --- a/content/browser/service_worker/service_worker_navigation_loader_unittest.cc +++ b/content/browser/service_worker/service_worker_navigation_loader_unittest.cc @@ -12,6 +12,7 @@ #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" #include "content/browser/loader/navigation_loader_interceptor.h" #include "content/browser/loader/single_request_url_loader_factory.h" #include "content/browser/service_worker/embedded_worker_test_helper.h" @@ -29,6 +30,7 @@ #include "net/ssl/ssl_info.h" #include "net/test/cert_test_util.h" #include "net/test/test_data_directory.h" +#include "services/network/public/cpp/features.h" #include "services/network/public/mojom/fetch_api.mojom.h" #include "services/network/public/mojom/url_response_head.mojom.h" #include "services/network/test/test_url_loader_client.h" @@ -82,6 +84,15 @@ blink::mojom::FetchAPIResponsePtr RedirectResponse( return response; } +blink::mojom::FetchAPIResponsePtr HeadersResponse( + const base::flat_map& headers) { + auto response = blink::mojom::FetchAPIResponse::New(); + response->status_code = 200; + response->status_text = "OK"; + response->headers.insert(headers.begin(), headers.end()); + return response; +} + // Simulates a service worker handling fetch events. The response can be // customized via RespondWith* functions. class FetchEventServiceWorker : public FakeServiceWorker { @@ -119,6 +130,14 @@ class FetchEventServiceWorker : public FakeServiceWorker { // Tells this worker to respond to fetch events with an error response. void RespondWithError() { response_mode_ = ResponseMode::kErrorResponse; } + // Tells this worker to respond to fetch events with a response containing + // specific headers. + void RespondWithHeaders( + const base::flat_map& headers) { + response_mode_ = ResponseMode::kHeaders; + headers_ = headers; + } + // Tells this worker to respond to fetch events with the redirect response. void RespondWithRedirectResponse(const GURL& new_url) { response_mode_ = ResponseMode::kRedirect; @@ -260,6 +279,13 @@ class FetchEventServiceWorker : public FakeServiceWorker { std::move(finish_callback) .Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED); break; + case ResponseMode::kHeaders: + response_callback->OnResponse( + HeadersResponse(headers_), + blink::mojom::ServiceWorkerFetchEventTiming::New()); + std::move(finish_callback) + .Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED); + break; } if (quit_closure_for_fetch_event_) @@ -276,7 +302,8 @@ class FetchEventServiceWorker : public FakeServiceWorker { kFailFetchEventDispatch, kDeferredResponse, kEarlyResponse, - kRedirect + kRedirect, + kHeaders }; ResponseMode response_mode_ = ResponseMode::kDefault; @@ -297,6 +324,9 @@ class FetchEventServiceWorker : public FakeServiceWorker { // For ResponseMode::kRedirect. GURL redirected_url_; + // For ResponseMode::kHeaders + base::flat_map headers_; + bool has_received_fetch_event_ = false; base::OnceClosure quit_closure_for_fetch_event_; @@ -959,5 +989,19 @@ TEST_F(ServiceWorkerNavigationLoaderTest, CancelNavigationDuringFetchEvent) { EXPECT_EQ(net::ERR_ABORTED, client_.completion_status().error_code); } +TEST_F(ServiceWorkerNavigationLoaderTest, ResponseWithCoop) { + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures({network::features::kCrossOriginOpenerPolicy}, + {}); + service_worker_->RespondWithHeaders( + {{"Cross-Origin-Opener-Policy", "same-origin"}}); + + // Perform the request. + StartRequest(CreateRequest()); + client_.RunUntilComplete(); + EXPECT_EQ(network::mojom::CrossOriginOpenerPolicy::kSameOrigin, + client_.response_head()->cross_origin_opener_policy); +} + } // namespace service_worker_navigation_loader_unittest } // namespace content diff --git a/content/common/service_worker/service_worker_loader_helpers.cc b/content/common/service_worker/service_worker_loader_helpers.cc index aebc580e1db3ea..35b3053acd5db9 100644 --- a/content/common/service_worker/service_worker_loader_helpers.cc +++ b/content/common/service_worker/service_worker_loader_helpers.cc @@ -18,6 +18,7 @@ #include "net/url_request/redirect_util.h" #include "services/network/public/cpp/content_security_policy/content_security_policy.h" #include "services/network/public/cpp/cross_origin_embedder_policy.h" +#include "services/network/public/cpp/cross_origin_opener_policy_parser.h" #include "services/network/public/cpp/features.h" #include "services/network/public/cpp/resource_request.h" #include "services/network/public/cpp/resource_request_body.h" @@ -144,6 +145,22 @@ void ServiceWorkerLoaderHelpers::SaveResponseHeaders( kCrossOriginEmbedderPolicyValueReportOnlyHeader); out_head->cross_origin_embedder_policy = coep; } + + // TODO(pmeuleman): Remove the code duplication with + // //services/network/url_loader.cc. + if (base::FeatureList::IsEnabled( + network::features::kCrossOriginOpenerPolicy)) { + // Parse the Cross-Origin-Opener-Policy header. + constexpr char kCrossOriginOpenerPolicyHeader[] = + "Cross-Origin-Opener-Policy"; + std::string raw_coop_string; + if (out_head->headers && + out_head->headers->GetNormalizedHeader(kCrossOriginOpenerPolicyHeader, + &raw_coop_string)) { + out_head->cross_origin_opener_policy = + network::ParseCrossOriginOpenerPolicyHeader(raw_coop_string); + } + } } // static