| // Copyright 2020 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 "content/browser/service_worker/service_worker_registry.h" |
| |
| #include "base/test/bind_test_util.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "content/browser/service_worker/embedded_worker_test_helper.h" |
| #include "content/browser/service_worker/service_worker_context_core.h" |
| #include "content/browser/service_worker/service_worker_test_utils.h" |
| #include "content/public/test/browser_task_environment.h" |
| #include "content/public/test/test_browser_context.h" |
| #include "content/public/test/test_utils.h" |
| #include "net/disk_cache/disk_cache.h" |
| #include "net/test/cert_test_util.h" |
| #include "net/test/test_data_directory.h" |
| #include "storage/browser/test/mock_special_storage_policy.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/common/loader/network_utils.h" |
| #include "third_party/blink/public/common/origin_trials/origin_trial_policy.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| struct GetStorageUsageForOriginResult { |
| blink::ServiceWorkerStatusCode status; |
| int64_t usage; |
| }; |
| |
| void FindCallback(base::OnceClosure quit_closure, |
| base::Optional<blink::ServiceWorkerStatusCode>* result, |
| scoped_refptr<ServiceWorkerRegistration>* found, |
| blink::ServiceWorkerStatusCode status, |
| scoped_refptr<ServiceWorkerRegistration> registration) { |
| *result = status; |
| *found = std::move(registration); |
| std::move(quit_closure).Run(); |
| } |
| |
| // This is a sample public key for testing the API. The corresponding private |
| // key (use this to generate new samples for this test file) is: |
| // |
| // 0x83, 0x67, 0xf4, 0xcd, 0x2a, 0x1f, 0x0e, 0x04, 0x0d, 0x43, 0x13, |
| // 0x4c, 0x67, 0xc4, 0xf4, 0x28, 0xc9, 0x90, 0x15, 0x02, 0xe2, 0xba, |
| // 0xfd, 0xbb, 0xfa, 0xbc, 0x92, 0x76, 0x8a, 0x2c, 0x4b, 0xc7, 0x75, |
| // 0x10, 0xac, 0xf9, 0x3a, 0x1c, 0xb8, 0xa9, 0x28, 0x70, 0xd2, 0x9a, |
| // 0xd0, 0x0b, 0x59, 0xe1, 0xac, 0x2b, 0xb7, 0xd5, 0xca, 0x1f, 0x64, |
| // 0x90, 0x08, 0x8e, 0xa8, 0xe0, 0x56, 0x3a, 0x04, 0xd0 |
| const uint8_t kTestPublicKey[] = { |
| 0x75, 0x10, 0xac, 0xf9, 0x3a, 0x1c, 0xb8, 0xa9, 0x28, 0x70, 0xd2, |
| 0x9a, 0xd0, 0x0b, 0x59, 0xe1, 0xac, 0x2b, 0xb7, 0xd5, 0xca, 0x1f, |
| 0x64, 0x90, 0x08, 0x8e, 0xa8, 0xe0, 0x56, 0x3a, 0x04, 0xd0, |
| }; |
| |
| } // namespace |
| |
| class ServiceWorkerRegistryTest : public testing::Test { |
| public: |
| ServiceWorkerRegistryTest() |
| : task_environment_(BrowserTaskEnvironment::IO_MAINLOOP) {} |
| |
| void SetUp() override { |
| CHECK(user_data_directory_.CreateUniqueTempDir()); |
| user_data_directory_path_ = user_data_directory_.GetPath(); |
| special_storage_policy_ = |
| base::MakeRefCounted<storage::MockSpecialStoragePolicy>(); |
| InitializeTestHelper(); |
| } |
| |
| void TearDown() override { |
| helper_.reset(); |
| disk_cache::FlushCacheThreadForTesting(); |
| content::RunAllTasksUntilIdle(); |
| } |
| |
| ServiceWorkerContextCore* context() { return helper_->context(); } |
| ServiceWorkerRegistry* registry() { return context()->registry(); } |
| |
| storage::MockSpecialStoragePolicy* special_storage_policy() { |
| return special_storage_policy_.get(); |
| } |
| |
| void InitializeTestHelper() { |
| helper_ = std::make_unique<EmbeddedWorkerTestHelper>( |
| user_data_directory_path_, special_storage_policy_.get()); |
| } |
| |
| void SimulateRestart() { |
| // Need to reset |helper_| then wait for scheduled tasks to be finished |
| // because |helper_| has TestBrowserContext and the dtor schedules storage |
| // cleanup tasks. |
| helper_.reset(); |
| base::RunLoop().RunUntilIdle(); |
| InitializeTestHelper(); |
| } |
| |
| std::vector<url::Origin> GetRegisteredOrigins() { |
| std::vector<url::Origin> result; |
| base::RunLoop loop; |
| registry()->GetRemoteStorageControl()->GetRegisteredOrigins( |
| base::BindLambdaForTesting( |
| [&](const std::vector<url::Origin>& origins) { |
| result = origins; |
| loop.Quit(); |
| })); |
| loop.Run(); |
| return result; |
| } |
| |
| blink::ServiceWorkerStatusCode FindRegistrationForClientUrl( |
| const GURL& document_url, |
| scoped_refptr<ServiceWorkerRegistration>* registration) { |
| base::Optional<blink::ServiceWorkerStatusCode> result; |
| base::RunLoop loop; |
| registry()->FindRegistrationForClientUrl( |
| document_url, base::BindOnce(&FindCallback, loop.QuitClosure(), &result, |
| registration)); |
| loop.Run(); |
| return result.value(); |
| } |
| |
| blink::ServiceWorkerStatusCode StoreRegistration( |
| scoped_refptr<ServiceWorkerRegistration> registration, |
| scoped_refptr<ServiceWorkerVersion> version) { |
| blink::ServiceWorkerStatusCode result; |
| base::RunLoop loop; |
| registry()->StoreRegistration( |
| registration.get(), version.get(), |
| base::BindLambdaForTesting([&](blink::ServiceWorkerStatusCode status) { |
| result = status; |
| loop.Quit(); |
| })); |
| loop.Run(); |
| return result; |
| } |
| |
| GetStorageUsageForOriginResult GetStorageUsageForOrigin( |
| const url::Origin& origin) { |
| GetStorageUsageForOriginResult result; |
| base::RunLoop loop; |
| registry()->GetStorageUsageForOrigin( |
| origin, base::BindLambdaForTesting( |
| [&](blink::ServiceWorkerStatusCode status, int64_t usage) { |
| result.status = status; |
| result.usage = usage; |
| loop.Quit(); |
| })); |
| loop.Run(); |
| return result; |
| } |
| |
| blink::ServiceWorkerStatusCode GetAllRegistrationsInfos( |
| std::vector<ServiceWorkerRegistrationInfo>* registrations) { |
| base::Optional<blink::ServiceWorkerStatusCode> result; |
| base::RunLoop loop; |
| registry()->GetAllRegistrationsInfos(base::BindLambdaForTesting( |
| [&](blink::ServiceWorkerStatusCode status, |
| const std::vector<ServiceWorkerRegistrationInfo>& infos) { |
| result = status; |
| *registrations = infos; |
| loop.Quit(); |
| })); |
| EXPECT_FALSE(result.has_value()); // always async |
| loop.Run(); |
| return result.value(); |
| } |
| |
| private: |
| // |user_data_directory_| must be declared first to preserve destructor order. |
| base::ScopedTempDir user_data_directory_; |
| base::FilePath user_data_directory_path_; |
| |
| BrowserTaskEnvironment task_environment_; |
| scoped_refptr<storage::MockSpecialStoragePolicy> special_storage_policy_; |
| std::unique_ptr<EmbeddedWorkerTestHelper> helper_; |
| }; |
| |
| TEST_F(ServiceWorkerRegistryTest, RegisteredOriginCount) { |
| { |
| base::HistogramTester histogram_tester; |
| EXPECT_TRUE(GetRegisteredOrigins().empty()); |
| histogram_tester.ExpectUniqueSample("ServiceWorker.RegisteredOriginCount", |
| 0, 1); |
| } |
| |
| std::pair<GURL, GURL> scope_and_script_pairs[] = { |
| {GURL("https://www.example.com/scope/"), |
| GURL("https://www.example.com/script.js")}, |
| {GURL("https://www.example.com/scope/foo"), |
| GURL("https://www.example.com/script.js")}, |
| {GURL("https://www.test.com/scope/foobar"), |
| GURL("https://www.test.com/script.js")}, |
| {GURL("https://example.com/scope/"), |
| GURL("https://example.com/script.js")}, |
| }; |
| std::vector<scoped_refptr<ServiceWorkerRegistration>> registrations; |
| int64_t dummy_resource_id = 1; |
| for (const auto& pair : scope_and_script_pairs) { |
| registrations.emplace_back(CreateServiceWorkerRegistrationAndVersion( |
| context(), pair.first, pair.second, dummy_resource_id)); |
| ++dummy_resource_id; |
| } |
| |
| // Store all registrations. |
| for (const auto& registration : registrations) { |
| EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, |
| StoreRegistration(registration, registration->waiting_version())); |
| } |
| |
| SimulateRestart(); |
| |
| { |
| base::HistogramTester histogram_tester; |
| EXPECT_EQ(3UL, GetRegisteredOrigins().size()); |
| histogram_tester.ExpectUniqueSample("ServiceWorker.RegisteredOriginCount", |
| 3, 1); |
| } |
| |
| // Re-initializing shouldn't re-record the histogram. |
| { |
| base::HistogramTester histogram_tester; |
| EXPECT_EQ(3UL, GetRegisteredOrigins().size()); |
| histogram_tester.ExpectTotalCount("ServiceWorker.RegisteredOriginCount", 0); |
| } |
| } |
| |
| TEST_F(ServiceWorkerRegistryTest, FindRegistration_LongestScopeMatch) { |
| const GURL kDocumentUrl("http://www.example.com/scope/foo"); |
| scoped_refptr<ServiceWorkerRegistration> found_registration; |
| |
| // Registration for "/scope/". |
| const GURL kScope1("http://www.example.com/scope/"); |
| const GURL kScript1("http://www.example.com/script1.js"); |
| scoped_refptr<ServiceWorkerRegistration> live_registration1 = |
| CreateServiceWorkerRegistrationAndVersion(context(), kScope1, kScript1, |
| /*resource_id=*/1); |
| |
| // Registration for "/scope/foo". |
| const GURL kScope2("http://www.example.com/scope/foo"); |
| const GURL kScript2("http://www.example.com/script2.js"); |
| scoped_refptr<ServiceWorkerRegistration> live_registration2 = |
| CreateServiceWorkerRegistrationAndVersion(context(), kScope2, kScript2, |
| /*resource_id=*/2); |
| |
| // Registration for "/scope/foobar". |
| const GURL kScope3("http://www.example.com/scope/foobar"); |
| const GURL kScript3("http://www.example.com/script3.js"); |
| scoped_refptr<ServiceWorkerRegistration> live_registration3 = |
| CreateServiceWorkerRegistrationAndVersion(context(), kScope3, kScript3, |
| /*resource_id=*/3); |
| |
| // Notify storage of them being installed. |
| registry()->NotifyInstallingRegistration(live_registration1.get()); |
| registry()->NotifyInstallingRegistration(live_registration2.get()); |
| registry()->NotifyInstallingRegistration(live_registration3.get()); |
| |
| // Find a registration among installing ones. |
| EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, |
| FindRegistrationForClientUrl(kDocumentUrl, &found_registration)); |
| EXPECT_EQ(live_registration2, found_registration); |
| found_registration = nullptr; |
| |
| // Store registrations. |
| EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, |
| StoreRegistration(live_registration1, |
| live_registration1->waiting_version())); |
| EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, |
| StoreRegistration(live_registration2, |
| live_registration2->waiting_version())); |
| EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, |
| StoreRegistration(live_registration3, |
| live_registration3->waiting_version())); |
| |
| // Notify storage of installations no longer happening. |
| registry()->NotifyDoneInstallingRegistration( |
| live_registration1.get(), nullptr, blink::ServiceWorkerStatusCode::kOk); |
| registry()->NotifyDoneInstallingRegistration( |
| live_registration2.get(), nullptr, blink::ServiceWorkerStatusCode::kOk); |
| registry()->NotifyDoneInstallingRegistration( |
| live_registration3.get(), nullptr, blink::ServiceWorkerStatusCode::kOk); |
| |
| // Find a registration among installed ones. |
| EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, |
| FindRegistrationForClientUrl(kDocumentUrl, &found_registration)); |
| EXPECT_EQ(live_registration2, found_registration); |
| } |
| |
| // Tests that fields of ServiceWorkerRegistrationInfo are filled correctly. |
| TEST_F(ServiceWorkerRegistryTest, RegistrationInfoFields) { |
| const GURL kScope("http://www.example.com/scope/"); |
| const GURL kScript("http://www.example.com/script1.js"); |
| scoped_refptr<ServiceWorkerRegistration> registration = |
| CreateServiceWorkerRegistrationAndVersion(context(), kScope, kScript, |
| /*resource_id=*/1); |
| |
| // Set some fields to check ServiceWorkerStorage serializes/deserializes |
| // these fields correctly. |
| registration->SetUpdateViaCache( |
| blink::mojom::ServiceWorkerUpdateViaCache::kImports); |
| registration->EnableNavigationPreload(true); |
| registration->SetNavigationPreloadHeader("header"); |
| |
| registry()->NotifyInstallingRegistration(registration.get()); |
| ASSERT_EQ(StoreRegistration(registration, registration->waiting_version()), |
| blink::ServiceWorkerStatusCode::kOk); |
| |
| std::vector<ServiceWorkerRegistrationInfo> all_registrations; |
| EXPECT_EQ(GetAllRegistrationsInfos(&all_registrations), |
| blink::ServiceWorkerStatusCode::kOk); |
| ASSERT_EQ(all_registrations.size(), 1UL); |
| |
| ServiceWorkerRegistrationInfo info = all_registrations[0]; |
| EXPECT_EQ(info.scope, registration->scope()); |
| EXPECT_EQ(info.update_via_cache, registration->update_via_cache()); |
| EXPECT_EQ(info.registration_id, registration->id()); |
| EXPECT_EQ(info.navigation_preload_enabled, |
| registration->navigation_preload_state().enabled); |
| EXPECT_EQ(info.navigation_preload_header_length, |
| registration->navigation_preload_state().header.size()); |
| } |
| |
| // Tests loading a registration with an enabled navigation preload state, as |
| // well as a custom header value. |
| TEST_F(ServiceWorkerRegistryTest, EnabledNavigationPreloadState) { |
| const GURL kScope("https://valid.example.com/scope"); |
| const GURL kScript("https://valid.example.com/script.js"); |
| const std::string kHeaderValue("custom header value"); |
| |
| scoped_refptr<ServiceWorkerRegistration> registration = |
| CreateServiceWorkerRegistrationAndVersion(context(), kScope, kScript, |
| /*resource_id=*/1); |
| ServiceWorkerVersion* version = registration->waiting_version(); |
| version->SetStatus(ServiceWorkerVersion::ACTIVATED); |
| registration->SetActiveVersion(version); |
| registration->EnableNavigationPreload(true); |
| registration->SetNavigationPreloadHeader(kHeaderValue); |
| |
| ASSERT_EQ(StoreRegistration(registration, version), |
| blink::ServiceWorkerStatusCode::kOk); |
| |
| // Simulate browser shutdown and restart. |
| registration = nullptr; |
| version = nullptr; |
| SimulateRestart(); |
| |
| scoped_refptr<ServiceWorkerRegistration> found_registration; |
| EXPECT_EQ(FindRegistrationForClientUrl(kScope, &found_registration), |
| blink::ServiceWorkerStatusCode::kOk); |
| const blink::mojom::NavigationPreloadState& registration_state = |
| found_registration->navigation_preload_state(); |
| EXPECT_TRUE(registration_state.enabled); |
| EXPECT_EQ(registration_state.header, kHeaderValue); |
| ASSERT_TRUE(found_registration->active_version()); |
| const blink::mojom::NavigationPreloadState& state = |
| found_registration->active_version()->navigation_preload_state(); |
| EXPECT_TRUE(state.enabled); |
| EXPECT_EQ(state.header, kHeaderValue); |
| } |
| |
| // Tests storing the script response time for DevTools. |
| TEST_F(ServiceWorkerRegistryTest, ScriptResponseTime) { |
| // Make a registration. |
| const GURL kScope("https://example.com/scope"); |
| const GURL kScript("https://example.com/script.js"); |
| scoped_refptr<ServiceWorkerRegistration> registration = |
| CreateServiceWorkerRegistrationAndVersion(context(), kScope, kScript, |
| /*resource_id=*/1); |
| ServiceWorkerVersion* version = registration->waiting_version(); |
| |
| // Give it a main script response info. |
| network::mojom::URLResponseHead response_head; |
| response_head.headers = |
| base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200 OK"); |
| response_head.response_time = base::Time::FromJsTime(19940123); |
| version->SetMainScriptResponse( |
| std::make_unique<ServiceWorkerVersion::MainScriptResponse>( |
| response_head)); |
| EXPECT_TRUE(version->main_script_response_); |
| EXPECT_EQ(response_head.response_time, |
| version->script_response_time_for_devtools_); |
| EXPECT_EQ(response_head.response_time, |
| version->GetInfo().script_response_time); |
| |
| // Store the registration. |
| EXPECT_EQ(StoreRegistration(registration, version), |
| blink::ServiceWorkerStatusCode::kOk); |
| |
| // Simulate browser shutdown and restart. |
| registration = nullptr; |
| version = nullptr; |
| SimulateRestart(); |
| |
| // Read the registration. The main script's response time should be gettable. |
| scoped_refptr<ServiceWorkerRegistration> found_registration; |
| EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, |
| FindRegistrationForClientUrl(kScope, &found_registration)); |
| ASSERT_TRUE(found_registration); |
| auto* waiting_version = found_registration->waiting_version(); |
| ASSERT_TRUE(waiting_version); |
| EXPECT_FALSE(waiting_version->main_script_response_); |
| EXPECT_EQ(response_head.response_time, |
| waiting_version->script_response_time_for_devtools_); |
| EXPECT_EQ(response_head.response_time, |
| waiting_version->GetInfo().script_response_time); |
| } |
| |
| // Tests loading a registration with a disabled navigation preload |
| // state. |
| TEST_F(ServiceWorkerRegistryTest, DisabledNavigationPreloadState) { |
| const GURL kScope("https://valid.example.com/scope"); |
| const GURL kScript("https://valid.example.com/script.js"); |
| scoped_refptr<ServiceWorkerRegistration> registration = |
| CreateServiceWorkerRegistrationAndVersion(context(), kScope, kScript, |
| /*resource_id=*/1); |
| ServiceWorkerVersion* version = registration->waiting_version(); |
| version->SetStatus(ServiceWorkerVersion::ACTIVATED); |
| registration->SetActiveVersion(version); |
| registration->EnableNavigationPreload(false); |
| |
| EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, |
| StoreRegistration(registration, version)); |
| |
| // Simulate browser shutdown and restart. |
| registration = nullptr; |
| version = nullptr; |
| SimulateRestart(); |
| |
| scoped_refptr<ServiceWorkerRegistration> found_registration; |
| EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, |
| FindRegistrationForClientUrl(kScope, &found_registration)); |
| const blink::mojom::NavigationPreloadState& registration_state = |
| found_registration->navigation_preload_state(); |
| EXPECT_FALSE(registration_state.enabled); |
| EXPECT_EQ("true", registration_state.header); |
| ASSERT_TRUE(found_registration->active_version()); |
| const blink::mojom::NavigationPreloadState& state = |
| found_registration->active_version()->navigation_preload_state(); |
| EXPECT_FALSE(state.enabled); |
| EXPECT_EQ("true", state.header); |
| } |
| |
| // Tests that storage policy changes are observed. |
| TEST_F(ServiceWorkerRegistryTest, StoragePolicyChange) { |
| const GURL kScope("http://www.example.com/scope/"); |
| const GURL kScriptUrl("http://www.example.com/script.js"); |
| const auto kOrigin(url::Origin::Create(kScope)); |
| |
| scoped_refptr<ServiceWorkerRegistration> registration = |
| CreateServiceWorkerRegistrationAndVersion(context(), kScope, kScriptUrl, |
| /*resource_id=*/1); |
| |
| ASSERT_EQ(StoreRegistration(registration, registration->waiting_version()), |
| blink::ServiceWorkerStatusCode::kOk); |
| EXPECT_FALSE(registry()->ShouldPurgeOnShutdown(kOrigin)); |
| |
| { |
| // Update storage policy to mark the origin should be purged on shutdown. |
| special_storage_policy()->AddSessionOnly(kOrigin.GetURL()); |
| special_storage_policy()->NotifyPolicyChanged(); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| EXPECT_TRUE(registry()->ShouldPurgeOnShutdown(kOrigin)); |
| } |
| |
| // Tests that callbacks of storage operations are always called even when the |
| // remote storage is disconnected. |
| TEST_F(ServiceWorkerRegistryTest, RemoteStorageDisconnection) { |
| const GURL kScope("http://www.example.com/scope/"); |
| const GURL kScriptUrl("http://www.example.com/script.js"); |
| const auto kOrigin(url::Origin::Create(kScope)); |
| |
| scoped_refptr<ServiceWorkerRegistration> registration = |
| CreateServiceWorkerRegistrationAndVersion(context(), kScope, kScriptUrl, |
| /*resource_id=*/1); |
| |
| ASSERT_EQ(StoreRegistration(registration, registration->waiting_version()), |
| blink::ServiceWorkerStatusCode::kOk); |
| |
| GetStorageUsageForOriginResult result = GetStorageUsageForOrigin(kOrigin); |
| ASSERT_EQ(result.status, blink::ServiceWorkerStatusCode::kOk); |
| |
| // This will disconnect mojo connection of the remote storage. |
| registry()->SimulateStorageRestartForTesting(); |
| |
| result = GetStorageUsageForOrigin(kOrigin); |
| ASSERT_EQ(result.status, |
| blink::ServiceWorkerStatusCode::kErrorStorageDisconnected); |
| |
| // The connection should be recovered automatically. |
| result = GetStorageUsageForOrigin(kOrigin); |
| ASSERT_EQ(result.status, blink::ServiceWorkerStatusCode::kOk); |
| } |
| |
| class ServiceWorkerRegistryOriginTrialsTest : public ServiceWorkerRegistryTest { |
| public: |
| ServiceWorkerRegistryOriginTrialsTest() { |
| blink::TrialTokenValidator::SetOriginTrialPolicyGetter(base::BindRepeating( |
| [](blink::OriginTrialPolicy* policy) { return policy; }, |
| base::Unretained(&origin_trial_policy_))); |
| } |
| |
| ~ServiceWorkerRegistryOriginTrialsTest() override { |
| blink::TrialTokenValidator::ResetOriginTrialPolicyGetter(); |
| } |
| |
| private: |
| class TestOriginTrialPolicy : public blink::OriginTrialPolicy { |
| public: |
| TestOriginTrialPolicy() { |
| public_keys_.emplace_back( |
| base::StringPiece(reinterpret_cast<const char*>(kTestPublicKey), |
| base::size(kTestPublicKey))); |
| } |
| |
| bool IsOriginTrialsSupported() const override { return true; } |
| |
| std::vector<base::StringPiece> GetPublicKeys() const override { |
| return public_keys_; |
| } |
| |
| bool IsOriginSecure(const GURL& url) const override { |
| return blink::network_utils::IsOriginSecure(url); |
| } |
| |
| private: |
| std::vector<base::StringPiece> public_keys_; |
| }; |
| |
| TestOriginTrialPolicy origin_trial_policy_; |
| }; |
| |
| TEST_F(ServiceWorkerRegistryOriginTrialsTest, FromMainScript) { |
| const GURL kScope("https://valid.example.com/scope"); |
| const GURL kScript("https://valid.example.com/script.js"); |
| const int64_t kRegistrationId = 1; |
| const int64_t kVersionId = 1; |
| blink::mojom::ServiceWorkerRegistrationOptions options; |
| options.scope = kScope; |
| scoped_refptr<ServiceWorkerRegistration> registration = |
| new ServiceWorkerRegistration(options, kRegistrationId, |
| context()->AsWeakPtr()); |
| scoped_refptr<ServiceWorkerVersion> version = new ServiceWorkerVersion( |
| registration.get(), kScript, blink::mojom::ScriptType::kClassic, |
| kVersionId, |
| mojo::PendingRemote<storage::mojom::ServiceWorkerLiveVersionRef>(), |
| context()->AsWeakPtr()); |
| |
| network::mojom::URLResponseHead response_head; |
| response_head.ssl_info = net::SSLInfo(); |
| response_head.ssl_info->cert = |
| net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem"); |
| EXPECT_TRUE(response_head.ssl_info->is_valid()); |
| // SSL3 TLS_DHE_RSA_WITH_AES_256_CBC_SHA |
| response_head.ssl_info->connection_status = 0x300039; |
| |
| const std::string kHTTPHeaderLine("HTTP/1.1 200 OK\n\n"); |
| const std::string kOriginTrial("Origin-Trial"); |
| // Token for Feature1 which expires 2033-05-18. |
| // generate_token.py valid.example.com Feature1 --expire-timestamp=2000000000 |
| // TODO(horo): Generate this sample token during the build. |
| const std::string kFeature1Token( |
| "AtiUXksymWhTv5ipBE7853JytiYb0RMj3wtEBjqu3PeufQPwV1oEaNjHt4R/oEBfcK0UiWlA" |
| "P2b9BE2/eThqcAYAAABYeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5leGFtcGxlLmNvbTo0" |
| "NDMiLCAiZmVhdHVyZSI6ICJGZWF0dXJlMSIsICJleHBpcnkiOiAyMDAwMDAwMDAwfQ=="); |
| // Token for Feature2 which expires 2033-05-18. |
| // generate_token.py valid.example.com Feature2 --expire-timestamp=2000000000 |
| // TODO(horo): Generate this sample token during the build. |
| const std::string kFeature2Token1( |
| "ApmHVC6Dpez0KQNBy13o6cGuoB5AgzOLN0keQMyAN5mjebCwR0MA8/IyjKQIlyom2RuJVg/u" |
| "LmnqEpldfewkbA8AAABYeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5leGFtcGxlLmNvbTo0" |
| "NDMiLCAiZmVhdHVyZSI6ICJGZWF0dXJlMiIsICJleHBpcnkiOiAyMDAwMDAwMDAwfQ=="); |
| // Token for Feature2 which expires 2036-07-18. |
| // generate_token.py valid.example.com Feature2 --expire-timestamp=2100000000 |
| // TODO(horo): Generate this sample token during the build. |
| const std::string kFeature2Token2( |
| "AmV2SSxrYstE2zSwZToy7brAbIJakd146apC/6+VDflLmc5yDfJlHGILe5+ZynlcliG7clOR" |
| "fHhXCzS5Lh1v4AAAAABYeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5leGFtcGxlLmNvbTo0" |
| "NDMiLCAiZmVhdHVyZSI6ICJGZWF0dXJlMiIsICJleHBpcnkiOiAyMTAwMDAwMDAwfQ=="); |
| // Token for Feature3 which expired 2001-09-09. |
| // generate_token.py valid.example.com Feature3 --expire-timestamp=1000000000 |
| const std::string kFeature3ExpiredToken( |
| "AtSAc03z4qvid34W4MHMxyRFUJKlubZ+P5cs5yg6EiBWcagVbnm5uBgJMJN34pag7D5RywGV" |
| "ol2RFf+4Sdm1hQ4AAABYeyJvcmlnaW4iOiAiaHR0cHM6Ly92YWxpZC5leGFtcGxlLmNvbTo0" |
| "NDMiLCAiZmVhdHVyZSI6ICJGZWF0dXJlMyIsICJleHBpcnkiOiAxMDAwMDAwMDAwfQ=="); |
| response_head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(""); |
| response_head.headers->AddHeader(kOriginTrial, kFeature1Token); |
| response_head.headers->AddHeader(kOriginTrial, kFeature2Token1); |
| response_head.headers->AddHeader(kOriginTrial, kFeature2Token2); |
| response_head.headers->AddHeader(kOriginTrial, kFeature3ExpiredToken); |
| version->SetMainScriptResponse( |
| std::make_unique<ServiceWorkerVersion::MainScriptResponse>( |
| response_head)); |
| ASSERT_TRUE(version->origin_trial_tokens()); |
| const blink::TrialTokenValidator::FeatureToTokensMap& tokens = |
| *version->origin_trial_tokens(); |
| ASSERT_EQ(2UL, tokens.size()); |
| ASSERT_EQ(1UL, tokens.at("Feature1").size()); |
| EXPECT_EQ(kFeature1Token, tokens.at("Feature1")[0]); |
| ASSERT_EQ(2UL, tokens.at("Feature2").size()); |
| EXPECT_EQ(kFeature2Token1, tokens.at("Feature2")[0]); |
| EXPECT_EQ(kFeature2Token2, tokens.at("Feature2")[1]); |
| |
| std::vector<storage::mojom::ServiceWorkerResourceRecordPtr> records; |
| records.push_back( |
| storage::mojom::ServiceWorkerResourceRecord::New(1, kScript, 100)); |
| version->script_cache_map()->SetResources(records); |
| version->set_fetch_handler_existence( |
| ServiceWorkerVersion::FetchHandlerExistence::EXISTS); |
| version->SetStatus(ServiceWorkerVersion::INSTALLED); |
| registration->SetActiveVersion(version); |
| |
| EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, |
| StoreRegistration(registration, version)); |
| // Simulate browser shutdown and restart. |
| registration = nullptr; |
| version = nullptr; |
| SimulateRestart(); |
| |
| scoped_refptr<ServiceWorkerRegistration> found_registration; |
| EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, |
| FindRegistrationForClientUrl(kScope, &found_registration)); |
| ASSERT_TRUE(found_registration->active_version()); |
| const blink::TrialTokenValidator::FeatureToTokensMap& found_tokens = |
| *found_registration->active_version()->origin_trial_tokens(); |
| ASSERT_EQ(2UL, found_tokens.size()); |
| ASSERT_EQ(1UL, found_tokens.at("Feature1").size()); |
| EXPECT_EQ(kFeature1Token, found_tokens.at("Feature1")[0]); |
| ASSERT_EQ(2UL, found_tokens.at("Feature2").size()); |
| EXPECT_EQ(kFeature2Token1, found_tokens.at("Feature2")[0]); |
| EXPECT_EQ(kFeature2Token2, found_tokens.at("Feature2")[1]); |
| } |
| |
| } // namespace content |