1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/browser/service_worker/service_worker_provider_host.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/macros.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/run_loop.h"
15 #include "base/test/scoped_feature_list.h"
16 #include "base/threading/thread_task_runner_handle.h"
17 #include "content/browser/frame_host/frame_tree_node.h"
18 #include "content/browser/service_worker/embedded_worker_test_helper.h"
19 #include "content/browser/service_worker/service_worker_container_host.h"
20 #include "content/browser/service_worker/service_worker_context_core.h"
21 #include "content/browser/service_worker/service_worker_register_job.h"
22 #include "content/browser/service_worker/service_worker_registration.h"
23 #include "content/browser/service_worker/service_worker_test_utils.h"
24 #include "content/browser/service_worker/service_worker_version.h"
25 #include "content/common/content_navigation_policy.h"
26 #include "content/common/url_schemes.h"
27 #include "content/public/common/child_process_host.h"
28 #include "content/public/common/content_features.h"
29 #include "content/public/common/origin_util.h"
30 #include "content/public/test/browser_task_environment.h"
31 #include "content/public/test/test_utils.h"
32 #include "content/test/test_content_browser_client.h"
33 #include "content/test/test_content_client.h"
34 #include "mojo/core/embedder/embedder.h"
35 #include "testing/gtest/include/gtest/gtest.h"
36 #include "third_party/blink/public/common/features.h"
37 #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h"
38 #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
39 #include "url/url_util.h"
40 
41 namespace content {
42 
43 namespace {
44 
45 const char kServiceWorkerScheme[] = "i-can-use-service-worker";
46 
47 class ServiceWorkerTestContentClient : public TestContentClient {
48  public:
AddAdditionalSchemes(Schemes * schemes)49   void AddAdditionalSchemes(Schemes* schemes) override {
50     schemes->service_worker_schemes.push_back(kServiceWorkerScheme);
51   }
52 };
53 
54 class ServiceWorkerTestContentBrowserClient : public TestContentBrowserClient {
55  public:
56   struct AllowServiceWorkerCallLog {
AllowServiceWorkerCallLogcontent::__anon1e68603a0111::ServiceWorkerTestContentBrowserClient::AllowServiceWorkerCallLog57     AllowServiceWorkerCallLog(
58         const GURL& scope,
59         const GURL& site_for_cookies,
60         const base::Optional<url::Origin>& top_frame_origin,
61         const GURL& script_url)
62         : scope(scope),
63           site_for_cookies(site_for_cookies),
64           top_frame_origin(top_frame_origin),
65           script_url(script_url) {}
66     const GURL scope;
67     const GURL site_for_cookies;
68     const base::Optional<url::Origin> top_frame_origin;
69     const GURL script_url;
70   };
71 
ServiceWorkerTestContentBrowserClient()72   ServiceWorkerTestContentBrowserClient() {}
73 
AllowServiceWorkerOnIO(const GURL & scope,const GURL & site_for_cookies,const base::Optional<url::Origin> & top_frame_origin,const GURL & script_url,content::ResourceContext * context,base::RepeatingCallback<WebContents * ()> wc_getter)74   bool AllowServiceWorkerOnIO(
75       const GURL& scope,
76       const GURL& site_for_cookies,
77       const base::Optional<url::Origin>& top_frame_origin,
78       const GURL& script_url,
79       content::ResourceContext* context,
80       base::RepeatingCallback<WebContents*()> wc_getter) override {
81     logs_.emplace_back(scope, site_for_cookies, top_frame_origin, script_url);
82     return false;
83   }
84 
AllowServiceWorkerOnUI(const GURL & scope,const GURL & site_for_cookies,const base::Optional<url::Origin> & top_frame_origin,const GURL & script_url,content::BrowserContext * context,base::RepeatingCallback<WebContents * ()> wc_getter)85   bool AllowServiceWorkerOnUI(
86       const GURL& scope,
87       const GURL& site_for_cookies,
88       const base::Optional<url::Origin>& top_frame_origin,
89       const GURL& script_url,
90       content::BrowserContext* context,
91       base::RepeatingCallback<WebContents*()> wc_getter) override {
92     logs_.emplace_back(scope, site_for_cookies, top_frame_origin, script_url);
93     return false;
94   }
95 
logs() const96   const std::vector<AllowServiceWorkerCallLog>& logs() const { return logs_; }
97 
98  private:
99   std::vector<AllowServiceWorkerCallLog> logs_;
100 };
101 
102 }  // namespace
103 
104 // TODO(https://crbug.com/931087): Rename ServiceWorkerProviderHostTest to
105 // ServiceWorkerContainerHostTest.
106 class ServiceWorkerProviderHostTest : public testing::Test {
107  protected:
ServiceWorkerProviderHostTest()108   ServiceWorkerProviderHostTest()
109       : task_environment_(BrowserTaskEnvironment::IO_MAINLOOP) {
110     SetContentClient(&test_content_client_);
111     ReRegisterContentSchemesForTests();
112   }
~ServiceWorkerProviderHostTest()113   ~ServiceWorkerProviderHostTest() override {}
114 
SetUp()115   void SetUp() override {
116     old_content_browser_client_ =
117         SetBrowserClientForTesting(&test_content_browser_client_);
118     mojo::core::SetDefaultProcessErrorCallback(base::BindRepeating(
119         &ServiceWorkerProviderHostTest::OnMojoError, base::Unretained(this)));
120 
121     helper_.reset(new EmbeddedWorkerTestHelper(base::FilePath()));
122     context_ = helper_->context();
123     script_url_ = GURL("https://www.example.com/service_worker.js");
124 
125     blink::mojom::ServiceWorkerRegistrationOptions options1;
126     options1.scope = GURL("https://www.example.com/");
127     registration1_ =
128         new ServiceWorkerRegistration(options1, 1L, context_->AsWeakPtr());
129 
130     blink::mojom::ServiceWorkerRegistrationOptions options2;
131     options2.scope = GURL("https://www.example.com/example");
132     registration2_ =
133         new ServiceWorkerRegistration(options2, 2L, context_->AsWeakPtr());
134 
135     blink::mojom::ServiceWorkerRegistrationOptions options3;
136     options3.scope = GURL("https://other.example.com/");
137     registration3_ =
138         new ServiceWorkerRegistration(options3, 3L, context_->AsWeakPtr());
139   }
140 
TearDown()141   void TearDown() override {
142     registration1_ = nullptr;
143     registration2_ = nullptr;
144     registration3_ = nullptr;
145     helper_.reset();
146     SetBrowserClientForTesting(old_content_browser_client_);
147     mojo::core::SetDefaultProcessErrorCallback(
148         mojo::core::ProcessErrorCallback());
149   }
150 
PrepareServiceWorkerContainerHost(const GURL & document_url)151   ServiceWorkerRemoteProviderEndpoint PrepareServiceWorkerContainerHost(
152       const GURL& document_url) {
153     ServiceWorkerRemoteProviderEndpoint remote_endpoint;
154     net::SiteForCookies site_for_cookies =
155         net::SiteForCookies::FromUrl(document_url);
156     url::Origin top_frame_origin = url::Origin::Create(document_url);
157     CreateContainerHostInternal(document_url, site_for_cookies,
158                                 top_frame_origin, &remote_endpoint);
159     return remote_endpoint;
160   }
161 
162   ServiceWorkerRemoteProviderEndpoint
PrepareServiceWorkerContainerHostWithSiteForCookies(const GURL & document_url,const net::SiteForCookies & site_for_cookies,const base::Optional<url::Origin> & top_frame_origin)163   PrepareServiceWorkerContainerHostWithSiteForCookies(
164       const GURL& document_url,
165       const net::SiteForCookies& site_for_cookies,
166       const base::Optional<url::Origin>& top_frame_origin) {
167     ServiceWorkerRemoteProviderEndpoint remote_endpoint;
168     CreateContainerHostInternal(document_url, site_for_cookies,
169                                 top_frame_origin, &remote_endpoint);
170     return remote_endpoint;
171   }
172 
CreateContainerHost(const GURL & document_url)173   base::WeakPtr<ServiceWorkerContainerHost> CreateContainerHost(
174       const GURL& document_url) {
175     net::SiteForCookies site_for_cookies =
176         net::SiteForCookies::FromUrl(document_url);
177     url::Origin top_frame_origin = url::Origin::Create(document_url);
178     remote_endpoints_.emplace_back();
179     return CreateContainerHostInternal(document_url, site_for_cookies,
180                                        top_frame_origin,
181                                        &remote_endpoints_.back());
182   }
183 
184   base::WeakPtr<ServiceWorkerContainerHost>
CreateContainerHostWithInsecureParentFrame(const GURL & document_url)185   CreateContainerHostWithInsecureParentFrame(const GURL& document_url) {
186     remote_endpoints_.emplace_back();
187     base::WeakPtr<ServiceWorkerContainerHost> container_host =
188         CreateContainerHostForWindow(helper_->mock_render_process_id(),
189                                      false /* is_parent_frame_secure */,
190                                      helper_->context()->AsWeakPtr(),
191                                      &remote_endpoints_.back());
192     container_host->UpdateUrls(document_url,
193                                net::SiteForCookies::FromUrl(document_url),
194                                url::Origin::Create(document_url));
195     return container_host;
196   }
197 
FinishNavigation(ServiceWorkerContainerHost * container_host)198   void FinishNavigation(ServiceWorkerContainerHost* container_host) {
199     // In production code, the loader/request handler does this.
200     const GURL url("https://www.example.com/page");
201     container_host->UpdateUrls(url, net::SiteForCookies::FromUrl(url),
202                                url::Origin::Create(url));
203 
204     // Establish a dummy connection to allow sending messages without errors.
205     mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
206         reporter;
207     auto dummy = reporter.InitWithNewPipeAndPassReceiver();
208 
209     // In production code this is called from NavigationRequest in the browser
210     // process right before navigation commit.
211     container_host->OnBeginNavigationCommit(
212         helper_->mock_render_process_id(), 1 /* route_id */,
213         network::CrossOriginEmbedderPolicy(), std::move(reporter));
214   }
215 
Register(blink::mojom::ServiceWorkerContainerHost * container_host,GURL scope,GURL worker_url)216   blink::mojom::ServiceWorkerErrorType Register(
217       blink::mojom::ServiceWorkerContainerHost* container_host,
218       GURL scope,
219       GURL worker_url) {
220     blink::mojom::ServiceWorkerErrorType error =
221         blink::mojom::ServiceWorkerErrorType::kUnknown;
222     auto options = blink::mojom::ServiceWorkerRegistrationOptions::New();
223     options->scope = scope;
224     container_host->Register(
225         worker_url, std::move(options),
226         blink::mojom::FetchClientSettingsObject::New(),
227         base::BindOnce([](blink::mojom::ServiceWorkerErrorType* out_error,
228                           blink::mojom::ServiceWorkerErrorType error,
229                           const base::Optional<std::string>& error_msg,
230                           blink::mojom::ServiceWorkerRegistrationObjectInfoPtr
231                               registration) { *out_error = error; },
232                        &error));
233     base::RunLoop().RunUntilIdle();
234     return error;
235   }
236 
GetRegistration(blink::mojom::ServiceWorkerContainerHost * container_host,GURL document_url,blink::mojom::ServiceWorkerRegistrationObjectInfoPtr * out_info=nullptr)237   blink::mojom::ServiceWorkerErrorType GetRegistration(
238       blink::mojom::ServiceWorkerContainerHost* container_host,
239       GURL document_url,
240       blink::mojom::ServiceWorkerRegistrationObjectInfoPtr* out_info =
241           nullptr) {
242     blink::mojom::ServiceWorkerErrorType error =
243         blink::mojom::ServiceWorkerErrorType::kUnknown;
244     container_host->GetRegistration(
245         document_url,
246         base::BindOnce(
247             [](blink::mojom::ServiceWorkerErrorType* out_error,
248                blink::mojom::ServiceWorkerRegistrationObjectInfoPtr* out_info,
249                blink::mojom::ServiceWorkerErrorType error,
250                const base::Optional<std::string>& error_msg,
251                blink::mojom::ServiceWorkerRegistrationObjectInfoPtr
252                    registration) {
253               *out_error = error;
254               if (out_info)
255                 *out_info = std::move(registration);
256             },
257             &error, out_info));
258     base::RunLoop().RunUntilIdle();
259     return error;
260   }
261 
GetRegistrations(blink::mojom::ServiceWorkerContainerHost * container_host)262   blink::mojom::ServiceWorkerErrorType GetRegistrations(
263       blink::mojom::ServiceWorkerContainerHost* container_host) {
264     blink::mojom::ServiceWorkerErrorType error =
265         blink::mojom::ServiceWorkerErrorType::kUnknown;
266     container_host->GetRegistrations(base::BindOnce(
267         [](blink::mojom::ServiceWorkerErrorType* out_error,
268            blink::mojom::ServiceWorkerErrorType error,
269            const base::Optional<std::string>& error_msg,
270            base::Optional<std::vector<
271                blink::mojom::ServiceWorkerRegistrationObjectInfoPtr>> infos) {
272           *out_error = error;
273         },
274         &error));
275     base::RunLoop().RunUntilIdle();
276     return error;
277   }
278 
OnMojoError(const std::string & error)279   void OnMojoError(const std::string& error) { bad_messages_.push_back(error); }
280 
CanFindClientContainerHost(ServiceWorkerContainerHost * container_host)281   bool CanFindClientContainerHost(ServiceWorkerContainerHost* container_host) {
282     for (std::unique_ptr<ServiceWorkerContextCore::ContainerHostIterator> it =
283              context_->GetClientContainerHostIterator(
284                  container_host->url().GetOrigin(),
285                  false /* include_reserved_clients */,
286                  false /* include_back_forward_cached_clients */);
287          !it->IsAtEnd(); it->Advance()) {
288       if (container_host == it->GetContainerHost())
289         return true;
290     }
291     return false;
292   }
293 
ExpectUpdateIsScheduled(ServiceWorkerVersion * version)294   void ExpectUpdateIsScheduled(ServiceWorkerVersion* version) {
295     EXPECT_TRUE(version->is_update_scheduled_);
296     EXPECT_TRUE(version->update_timer_.IsRunning());
297   }
298 
ExpectUpdateIsNotScheduled(ServiceWorkerVersion * version)299   void ExpectUpdateIsNotScheduled(ServiceWorkerVersion* version) {
300     EXPECT_FALSE(version->is_update_scheduled_);
301     EXPECT_FALSE(version->update_timer_.IsRunning());
302   }
303 
HasVersionToUpdate(ServiceWorkerContainerHost * container_host)304   bool HasVersionToUpdate(ServiceWorkerContainerHost* container_host) {
305     return !container_host->versions_to_update_.empty();
306   }
307 
308   void TestReservedClientsAreNotExposed(
309       blink::mojom::ServiceWorkerContainerType provider_type,
310       const GURL& url);
311   void TestClientPhaseTransition(
312       blink::mojom::ServiceWorkerContainerType provider_type,
313       const GURL& url);
314 
315   void TestBackForwardCachedClientsAreNotExposed(
316       blink::mojom::ServiceWorkerContainerType provider_type,
317       const GURL& url);
318 
319   BrowserTaskEnvironment task_environment_;
320 
321   std::unique_ptr<EmbeddedWorkerTestHelper> helper_;
322   ServiceWorkerContextCore* context_;
323   scoped_refptr<ServiceWorkerRegistration> registration1_;
324   scoped_refptr<ServiceWorkerRegistration> registration2_;
325   scoped_refptr<ServiceWorkerRegistration> registration3_;
326   GURL script_url_;
327   ServiceWorkerTestContentClient test_content_client_;
328   TestContentBrowserClient test_content_browser_client_;
329   ContentBrowserClient* old_content_browser_client_;
330   std::vector<ServiceWorkerRemoteProviderEndpoint> remote_endpoints_;
331   std::vector<std::string> bad_messages_;
332 
333  private:
CreateContainerHostInternal(const GURL & document_url,const net::SiteForCookies & site_for_cookies,const base::Optional<url::Origin> & top_frame_origin,ServiceWorkerRemoteProviderEndpoint * remote_endpoint)334   base::WeakPtr<ServiceWorkerContainerHost> CreateContainerHostInternal(
335       const GURL& document_url,
336       const net::SiteForCookies& site_for_cookies,
337       const base::Optional<url::Origin>& top_frame_origin,
338       ServiceWorkerRemoteProviderEndpoint* remote_endpoint) {
339     base::WeakPtr<ServiceWorkerContainerHost> container_host =
340         CreateContainerHostForWindow(helper_->mock_render_process_id(),
341                                      true /* is_parent_frame_secure */,
342                                      helper_->context()->AsWeakPtr(),
343                                      remote_endpoint);
344     container_host->UpdateUrls(document_url, site_for_cookies,
345                                top_frame_origin);
346     return container_host;
347   }
348 
349   url::ScopedSchemeRegistryForTests scoped_registry_;
350 
351   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerProviderHostTest);
352 };
353 
354 // Run tests with PlzDedicatedWorker.
355 // TODO(https://crbug.com/906991): Merge this test fixture into
356 // ServiceWorkerProviderHostTest once PlzDedicatedWorker is enabled by default.
357 class ServiceWorkerProviderHostTestWithPlzDedicatedWorker
358     : public ServiceWorkerProviderHostTest {
359  public:
ServiceWorkerProviderHostTestWithPlzDedicatedWorker()360   ServiceWorkerProviderHostTestWithPlzDedicatedWorker() {
361     // ServiceWorkerProviderHost for dedicated workers is available only when
362     // PlzDedicatedWorker is enabled.
363     scoped_feature_list_.InitAndEnableFeature(
364         blink::features::kPlzDedicatedWorker);
365   }
366 
367  private:
368   base::test::ScopedFeatureList scoped_feature_list_;
369 };
370 
TEST_F(ServiceWorkerProviderHostTest,MatchRegistration)371 TEST_F(ServiceWorkerProviderHostTest, MatchRegistration) {
372   base::WeakPtr<ServiceWorkerContainerHost> container_host =
373       CreateContainerHost(GURL("https://www.example.com/example1.html"));
374 
375   // Match registration should return the longest matching one.
376   ASSERT_EQ(registration2_, container_host->MatchRegistration());
377   container_host->RemoveMatchingRegistration(registration2_.get());
378   ASSERT_EQ(registration1_, container_host->MatchRegistration());
379 
380   // Should return nullptr after removing all matching registrations.
381   container_host->RemoveMatchingRegistration(registration1_.get());
382   ASSERT_EQ(nullptr, container_host->MatchRegistration());
383 
384   // SetDocumentUrl sets all of matching registrations
385   container_host->UpdateUrls(
386       GURL("https://www.example.com/example1"),
387       net::SiteForCookies::FromUrl(GURL("https://www.example.com/example1")),
388       url::Origin::Create(GURL("https://www.example.com/example1")));
389   ASSERT_EQ(registration2_, container_host->MatchRegistration());
390   container_host->RemoveMatchingRegistration(registration2_.get());
391   ASSERT_EQ(registration1_, container_host->MatchRegistration());
392 
393   // SetDocumentUrl with another origin also updates matching registrations
394   container_host->UpdateUrls(
395       GURL("https://other.example.com/example"),
396       net::SiteForCookies::FromUrl(GURL("https://other.example.com/example")),
397       url::Origin::Create(GURL("https://other.example.com/example")));
398   ASSERT_EQ(registration3_, container_host->MatchRegistration());
399   container_host->RemoveMatchingRegistration(registration3_.get());
400   ASSERT_EQ(nullptr, container_host->MatchRegistration());
401 }
402 
TEST_F(ServiceWorkerProviderHostTest,ContextSecurity)403 TEST_F(ServiceWorkerProviderHostTest, ContextSecurity) {
404   base::WeakPtr<ServiceWorkerContainerHost> container_host_secure_parent =
405       CreateContainerHost(GURL("https://www.example.com/example1.html"));
406   base::WeakPtr<ServiceWorkerContainerHost> container_host_insecure_parent =
407       CreateContainerHostWithInsecureParentFrame(
408           GURL("https://www.example.com/example1.html"));
409 
410   // Insecure document URL.
411   container_host_secure_parent->UpdateUrls(
412       GURL("http://host"), net::SiteForCookies::FromUrl(GURL("http://host")),
413       url::Origin::Create(GURL("http://host")));
414   EXPECT_FALSE(container_host_secure_parent->IsContextSecureForServiceWorker());
415 
416   // Insecure parent frame.
417   container_host_insecure_parent->UpdateUrls(
418       GURL("https://host"), net::SiteForCookies::FromUrl(GURL("https://host")),
419       url::Origin::Create(GURL("https://host")));
420   EXPECT_FALSE(
421       container_host_insecure_parent->IsContextSecureForServiceWorker());
422 
423   // Secure URL and parent frame.
424   container_host_secure_parent->UpdateUrls(
425       GURL("https://host"), net::SiteForCookies::FromUrl(GURL("https://host")),
426       url::Origin::Create(GURL("https://host")));
427   EXPECT_TRUE(container_host_secure_parent->IsContextSecureForServiceWorker());
428 
429   // Exceptional service worker scheme.
430   GURL url(std::string(kServiceWorkerScheme) + "://host");
431   url::Origin origin = url::Origin::Create(url);
432   EXPECT_TRUE(url.is_valid());
433   EXPECT_FALSE(IsOriginSecure(url));
434   EXPECT_TRUE(OriginCanAccessServiceWorkers(url));
435   container_host_secure_parent->UpdateUrls(
436       url, net::SiteForCookies::FromUrl(url), origin);
437   EXPECT_TRUE(container_host_secure_parent->IsContextSecureForServiceWorker());
438 
439   // Exceptional service worker scheme with insecure parent frame.
440   container_host_insecure_parent->UpdateUrls(
441       url, net::SiteForCookies::FromUrl(url), origin);
442   EXPECT_FALSE(
443       container_host_insecure_parent->IsContextSecureForServiceWorker());
444 }
445 
TEST_F(ServiceWorkerProviderHostTest,UpdateUrls_SameOriginRedirect)446 TEST_F(ServiceWorkerProviderHostTest, UpdateUrls_SameOriginRedirect) {
447   const GURL url1("https://origin1.example.com/page1.html");
448   const GURL url2("https://origin1.example.com/page2.html");
449 
450   base::WeakPtr<ServiceWorkerContainerHost> container_host =
451       CreateContainerHost(url1);
452   const std::string uuid1 = container_host->client_uuid();
453   EXPECT_EQ(url1, container_host->url());
454   EXPECT_TRUE(container_host->site_for_cookies().IsEquivalent(
455       net::SiteForCookies::FromUrl(url1)));
456 
457   container_host->UpdateUrls(url2, net::SiteForCookies::FromUrl(url2),
458                              url::Origin::Create(url2));
459   EXPECT_EQ(url2, container_host->url());
460   EXPECT_TRUE(container_host->site_for_cookies().IsEquivalent(
461       net::SiteForCookies::FromUrl(url2)));
462   EXPECT_EQ(uuid1, container_host->client_uuid());
463 
464   EXPECT_EQ(container_host.get(), context_->GetContainerHostByClientID(
465                                       container_host->client_uuid()));
466 }
467 
TEST_F(ServiceWorkerProviderHostTest,UpdateUrls_CrossOriginRedirect)468 TEST_F(ServiceWorkerProviderHostTest, UpdateUrls_CrossOriginRedirect) {
469   const GURL url1("https://origin1.example.com/page1.html");
470   const GURL url2("https://origin2.example.com/page2.html");
471 
472   base::WeakPtr<ServiceWorkerContainerHost> container_host =
473       CreateContainerHost(url1);
474   const std::string uuid1 = container_host->client_uuid();
475   EXPECT_EQ(url1, container_host->url());
476   EXPECT_TRUE(container_host->site_for_cookies().IsEquivalent(
477       net::SiteForCookies::FromUrl(url1)));
478 
479   container_host->UpdateUrls(url2, net::SiteForCookies::FromUrl(url2),
480                              url::Origin::Create(url2));
481   EXPECT_EQ(url2, container_host->url());
482   EXPECT_TRUE(container_host->site_for_cookies().IsEquivalent(
483       net::SiteForCookies::FromUrl(url2)));
484   EXPECT_NE(uuid1, container_host->client_uuid());
485 
486   EXPECT_FALSE(context_->GetContainerHostByClientID(uuid1));
487   EXPECT_EQ(container_host.get(), context_->GetContainerHostByClientID(
488                                       container_host->client_uuid()));
489 }
490 
491 class MockServiceWorkerRegistration : public ServiceWorkerRegistration {
492  public:
MockServiceWorkerRegistration(const blink::mojom::ServiceWorkerRegistrationOptions & options,int64_t registration_id,base::WeakPtr<ServiceWorkerContextCore> context)493   MockServiceWorkerRegistration(
494       const blink::mojom::ServiceWorkerRegistrationOptions& options,
495       int64_t registration_id,
496       base::WeakPtr<ServiceWorkerContextCore> context)
497       : ServiceWorkerRegistration(options, registration_id, context) {}
498 
AddListener(ServiceWorkerRegistration::Listener * listener)499   void AddListener(ServiceWorkerRegistration::Listener* listener) override {
500     listeners_.insert(listener);
501   }
502 
RemoveListener(ServiceWorkerRegistration::Listener * listener)503   void RemoveListener(ServiceWorkerRegistration::Listener* listener) override {
504     listeners_.erase(listener);
505   }
506 
listeners()507   const std::set<ServiceWorkerRegistration::Listener*>& listeners() {
508     return listeners_;
509   }
510 
511  protected:
~MockServiceWorkerRegistration()512   ~MockServiceWorkerRegistration() override {}
513 
514  private:
515   std::set<ServiceWorkerRegistration::Listener*> listeners_;
516 };
517 
TEST_F(ServiceWorkerProviderHostTest,RemoveProvider)518 TEST_F(ServiceWorkerProviderHostTest, RemoveProvider) {
519   // Create a container host connected with the renderer process.
520   base::WeakPtr<ServiceWorkerContainerHost> container_host =
521       CreateContainerHost(GURL("https://www.example.com/example1.html"));
522   EXPECT_TRUE(container_host);
523 
524   // Disconnect the mojo pipe from the renderer side.
525   ASSERT_TRUE(remote_endpoints_.back().host_remote()->is_bound());
526   remote_endpoints_.back().host_remote()->reset();
527   base::RunLoop().RunUntilIdle();
528   EXPECT_FALSE(container_host);
529 }
530 
531 class MockServiceWorkerContainer : public blink::mojom::ServiceWorkerContainer {
532  public:
MockServiceWorkerContainer(mojo::PendingAssociatedReceiver<blink::mojom::ServiceWorkerContainer> receiver)533   explicit MockServiceWorkerContainer(
534       mojo::PendingAssociatedReceiver<blink::mojom::ServiceWorkerContainer>
535           receiver)
536       : receiver_(this, std::move(receiver)) {}
537 
538   ~MockServiceWorkerContainer() override = default;
539 
SetController(blink::mojom::ControllerServiceWorkerInfoPtr controller_info,bool should_notify_controllerchange)540   void SetController(
541       blink::mojom::ControllerServiceWorkerInfoPtr controller_info,
542       bool should_notify_controllerchange) override {
543     was_set_controller_called_ = true;
544   }
PostMessageToClient(blink::mojom::ServiceWorkerObjectInfoPtr controller,blink::TransferableMessage message)545   void PostMessageToClient(blink::mojom::ServiceWorkerObjectInfoPtr controller,
546                            blink::TransferableMessage message) override {}
CountFeature(blink::mojom::WebFeature feature)547   void CountFeature(blink::mojom::WebFeature feature) override {}
548 
was_set_controller_called() const549   bool was_set_controller_called() const { return was_set_controller_called_; }
550 
551  private:
552   bool was_set_controller_called_ = false;
553   mojo::AssociatedReceiver<blink::mojom::ServiceWorkerContainer> receiver_;
554 };
555 
TEST_F(ServiceWorkerProviderHostTest,Controller)556 TEST_F(ServiceWorkerProviderHostTest, Controller) {
557   // Create a host.
558   std::unique_ptr<ServiceWorkerContainerHostAndInfo> host_and_info =
559       CreateContainerHostAndInfoForWindow(helper_->context()->AsWeakPtr(),
560                                           /*are_ancestors_secure=*/true);
561   base::WeakPtr<ServiceWorkerContainerHost> container_host =
562       std::move(host_and_info->host);
563   remote_endpoints_.emplace_back();
564   remote_endpoints_.back().BindForWindow(std::move(host_and_info->info));
565   auto container = std::make_unique<MockServiceWorkerContainer>(
566       std::move(*remote_endpoints_.back().client_receiver()));
567 
568   // Create an active version and then start the navigation.
569   scoped_refptr<ServiceWorkerVersion> version = new ServiceWorkerVersion(
570       registration1_.get(), GURL("https://www.example.com/sw.js"),
571       blink::mojom::ScriptType::kClassic, 1 /* version_id */,
572       helper_->context()->AsWeakPtr());
573   version->set_fetch_handler_existence(
574       ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
575   version->SetStatus(ServiceWorkerVersion::ACTIVATED);
576   registration1_->SetActiveVersion(version);
577 
578   // Finish the navigation.
579   FinishNavigation(container_host.get());
580   container_host->SetControllerRegistration(
581       registration1_, false /* notify_controllerchange */);
582   remote_endpoints_.back().host_remote()->get()->OnExecutionReady();
583   base::RunLoop().RunUntilIdle();
584 
585   // The page should be controlled since there was an active version at the
586   // time navigation started. The SetController IPC should have been sent.
587   EXPECT_TRUE(container_host->controller());
588   EXPECT_TRUE(container->was_set_controller_called());
589   EXPECT_EQ(registration1_.get(), container_host->MatchRegistration());
590 }
591 
TEST_F(ServiceWorkerProviderHostTest,UncontrolledWithMatchingRegistration)592 TEST_F(ServiceWorkerProviderHostTest, UncontrolledWithMatchingRegistration) {
593   // Create a host.
594   std::unique_ptr<ServiceWorkerContainerHostAndInfo> host_and_info =
595       CreateContainerHostAndInfoForWindow(helper_->context()->AsWeakPtr(),
596                                           /*are_ancestors_secure=*/true);
597   base::WeakPtr<ServiceWorkerContainerHost> container_host =
598       std::move(host_and_info->host);
599   remote_endpoints_.emplace_back();
600   remote_endpoints_.back().BindForWindow(std::move(host_and_info->info));
601   auto container = std::make_unique<MockServiceWorkerContainer>(
602       std::move(*remote_endpoints_.back().client_receiver()));
603 
604   // Create an installing version and then start the navigation.
605   scoped_refptr<ServiceWorkerVersion> version = new ServiceWorkerVersion(
606       registration1_.get(), GURL("https://www.example.com/sw.js"),
607       blink::mojom::ScriptType::kClassic, 1 /* version_id */,
608       helper_->context()->AsWeakPtr());
609   registration1_->SetInstallingVersion(version);
610 
611   // Finish the navigation.
612   FinishNavigation(container_host.get());
613   // Promote the worker to active while navigation is still happening.
614   registration1_->SetActiveVersion(version);
615   base::RunLoop().RunUntilIdle();
616 
617   // The page should not be controlled since there was no active version at the
618   // time navigation started. Furthermore, no SetController IPC should have been
619   // sent.
620   EXPECT_FALSE(container_host->controller());
621   EXPECT_FALSE(container->was_set_controller_called());
622   // However, the host should know the registration is its best match, for
623   // .ready and claim().
624   EXPECT_EQ(registration1_.get(), container_host->MatchRegistration());
625 }
626 
TEST_F(ServiceWorkerProviderHostTest,Register_ContentSettingsDisallowsServiceWorker)627 TEST_F(ServiceWorkerProviderHostTest,
628        Register_ContentSettingsDisallowsServiceWorker) {
629   ServiceWorkerTestContentBrowserClient test_browser_client;
630   ContentBrowserClient* old_browser_client =
631       SetBrowserClientForTesting(&test_browser_client);
632 
633   ServiceWorkerRemoteProviderEndpoint remote_endpoint =
634       PrepareServiceWorkerContainerHostWithSiteForCookies(
635           GURL("https://www.example.com/foo"),
636           net::SiteForCookies::FromUrl(GURL("https://www.example.com/top")),
637           url::Origin::Create(GURL("https://www.example.com")));
638 
639   EXPECT_EQ(blink::mojom::ServiceWorkerErrorType::kDisabled,
640             Register(remote_endpoint.host_remote()->get(),
641                      GURL("https://www.example.com/scope"),
642                      GURL("https://www.example.com/bar")));
643   ASSERT_EQ(1ul, test_browser_client.logs().size());
644   EXPECT_EQ(GURL("https://www.example.com/scope"),
645             test_browser_client.logs()[0].scope);
646   EXPECT_TRUE(net::SiteForCookies::FromUrl(
647                   test_browser_client.logs()[0].site_for_cookies)
648                   .IsEquivalent(net::SiteForCookies::FromUrl(
649                       GURL("https://www.example.com/top"))));
650   EXPECT_EQ(url::Origin::Create(GURL("https://www.example.com")),
651             test_browser_client.logs()[0].top_frame_origin);
652   EXPECT_EQ(GURL("https://www.example.com/bar"),
653             test_browser_client.logs()[0].script_url);
654 
655   EXPECT_EQ(blink::mojom::ServiceWorkerErrorType::kDisabled,
656             GetRegistration(remote_endpoint.host_remote()->get(),
657                             GURL("https://www.example.com/")));
658   ASSERT_EQ(2ul, test_browser_client.logs().size());
659   EXPECT_EQ(GURL("https://www.example.com/foo"),
660             test_browser_client.logs()[1].scope);
661   EXPECT_TRUE(net::SiteForCookies::FromUrl(
662                   test_browser_client.logs()[1].site_for_cookies)
663                   .IsEquivalent(net::SiteForCookies::FromUrl(
664                       GURL("https://www.example.com/top"))));
665 
666   EXPECT_EQ(url::Origin::Create(GURL("https://www.example.com")),
667             test_browser_client.logs()[1].top_frame_origin);
668   EXPECT_EQ(GURL(), test_browser_client.logs()[1].script_url);
669 
670   EXPECT_EQ(blink::mojom::ServiceWorkerErrorType::kDisabled,
671             GetRegistrations(remote_endpoint.host_remote()->get()));
672   ASSERT_EQ(3ul, test_browser_client.logs().size());
673   EXPECT_EQ(GURL("https://www.example.com/foo"),
674             test_browser_client.logs()[2].scope);
675   EXPECT_TRUE(net::SiteForCookies::FromUrl(
676                   test_browser_client.logs()[2].site_for_cookies)
677                   .IsEquivalent(net::SiteForCookies::FromUrl(
678                       GURL("https://www.example.com/top"))));
679   EXPECT_EQ(url::Origin::Create(GURL("https://www.example.com")),
680             *test_browser_client.logs()[2].top_frame_origin);
681   EXPECT_EQ(GURL(), test_browser_client.logs()[2].script_url);
682 
683   SetBrowserClientForTesting(old_browser_client);
684 }
685 
TEST_F(ServiceWorkerProviderHostTest,AllowsServiceWorker)686 TEST_F(ServiceWorkerProviderHostTest, AllowsServiceWorker) {
687   // Create an active version.
688   scoped_refptr<ServiceWorkerVersion> version =
689       base::MakeRefCounted<ServiceWorkerVersion>(
690           registration1_.get(), GURL("https://www.example.com/sw.js"),
691           blink::mojom::ScriptType::kClassic, 1 /* version_id */,
692           helper_->context()->AsWeakPtr());
693   registration1_->SetActiveVersion(version);
694 
695   ServiceWorkerRemoteProviderEndpoint remote_endpoint;
696   std::unique_ptr<ServiceWorkerProviderHost> provider_host =
697       CreateProviderHostForServiceWorkerContext(
698           helper_->mock_render_process_id(), true /* is_parent_frame_secure */,
699           version.get(), helper_->context()->AsWeakPtr(), &remote_endpoint);
700   ServiceWorkerContainerHost* container_host = provider_host->container_host();
701 
702   ServiceWorkerTestContentBrowserClient test_browser_client;
703   ContentBrowserClient* old_browser_client =
704       SetBrowserClientForTesting(&test_browser_client);
705 
706   EXPECT_FALSE(container_host->AllowServiceWorker(
707       GURL("https://www.example.com/scope"), GURL()));
708 
709   ASSERT_EQ(1ul, test_browser_client.logs().size());
710   EXPECT_EQ(GURL("https://www.example.com/scope"),
711             test_browser_client.logs()[0].scope);
712   EXPECT_TRUE(net::SiteForCookies::FromUrl(
713                   test_browser_client.logs()[0].site_for_cookies)
714                   .IsEquivalent(net::SiteForCookies::FromUrl(
715                       GURL("https://www.example.com/sw.js"))));
716   EXPECT_EQ(url::Origin::Create(GURL("https://www.example.com")),
717             test_browser_client.logs()[0].top_frame_origin);
718   SetBrowserClientForTesting(old_browser_client);
719 }
720 
TEST_F(ServiceWorkerProviderHostTest,Register_HTTPS)721 TEST_F(ServiceWorkerProviderHostTest, Register_HTTPS) {
722   ServiceWorkerRemoteProviderEndpoint remote_endpoint =
723       PrepareServiceWorkerContainerHost(GURL("https://www.example.com/foo"));
724 
725   EXPECT_EQ(blink::mojom::ServiceWorkerErrorType::kNone,
726             Register(remote_endpoint.host_remote()->get(),
727                      GURL("https://www.example.com/"),
728                      GURL("https://www.example.com/bar")));
729 }
730 
TEST_F(ServiceWorkerProviderHostTest,Register_NonSecureTransportLocalhost)731 TEST_F(ServiceWorkerProviderHostTest, Register_NonSecureTransportLocalhost) {
732   ServiceWorkerRemoteProviderEndpoint remote_endpoint =
733       PrepareServiceWorkerContainerHost(GURL("http://127.0.0.3:81/foo"));
734 
735   EXPECT_EQ(blink::mojom::ServiceWorkerErrorType::kNone,
736             Register(remote_endpoint.host_remote()->get(),
737                      GURL("http://127.0.0.3:81/bar"),
738                      GURL("http://127.0.0.3:81/baz")));
739 }
740 
TEST_F(ServiceWorkerProviderHostTest,Register_InvalidScopeShouldFail)741 TEST_F(ServiceWorkerProviderHostTest, Register_InvalidScopeShouldFail) {
742   ServiceWorkerRemoteProviderEndpoint remote_endpoint =
743       PrepareServiceWorkerContainerHost(GURL("https://www.example.com/foo"));
744 
745   ASSERT_TRUE(bad_messages_.empty());
746   Register(remote_endpoint.host_remote()->get(), GURL(""),
747            GURL("https://www.example.com/bar/hoge.js"));
748   EXPECT_EQ(1u, bad_messages_.size());
749 }
750 
TEST_F(ServiceWorkerProviderHostTest,Register_InvalidScriptShouldFail)751 TEST_F(ServiceWorkerProviderHostTest, Register_InvalidScriptShouldFail) {
752   ServiceWorkerRemoteProviderEndpoint remote_endpoint =
753       PrepareServiceWorkerContainerHost(GURL("https://www.example.com/foo"));
754 
755   ASSERT_TRUE(bad_messages_.empty());
756   Register(remote_endpoint.host_remote()->get(),
757            GURL("https://www.example.com/bar/"), GURL(""));
758   EXPECT_EQ(1u, bad_messages_.size());
759 }
760 
TEST_F(ServiceWorkerProviderHostTest,Register_NonSecureOriginShouldFail)761 TEST_F(ServiceWorkerProviderHostTest, Register_NonSecureOriginShouldFail) {
762   ServiceWorkerRemoteProviderEndpoint remote_endpoint =
763       PrepareServiceWorkerContainerHost(GURL("http://www.example.com/foo"));
764 
765   ASSERT_TRUE(bad_messages_.empty());
766   Register(remote_endpoint.host_remote()->get(),
767            GURL("http://www.example.com/"), GURL("http://www.example.com/bar"));
768   EXPECT_EQ(1u, bad_messages_.size());
769 }
770 
TEST_F(ServiceWorkerProviderHostTest,Register_CrossOriginShouldFail)771 TEST_F(ServiceWorkerProviderHostTest, Register_CrossOriginShouldFail) {
772   ServiceWorkerRemoteProviderEndpoint remote_endpoint =
773       PrepareServiceWorkerContainerHost(GURL("https://www.example.com/foo"));
774 
775   ASSERT_TRUE(bad_messages_.empty());
776   // Script has a different host
777   Register(remote_endpoint.host_remote()->get(),
778            GURL("https://www.example.com/"),
779            GURL("https://foo.example.com/bar"));
780   EXPECT_EQ(1u, bad_messages_.size());
781 
782   // Scope has a different host
783   Register(remote_endpoint.host_remote()->get(),
784            GURL("https://foo.example.com/"),
785            GURL("https://www.example.com/bar"));
786   EXPECT_EQ(2u, bad_messages_.size());
787 
788   // Script has a different port
789   Register(remote_endpoint.host_remote()->get(),
790            GURL("https://www.example.com/"),
791            GURL("https://www.example.com:8080/bar"));
792   EXPECT_EQ(3u, bad_messages_.size());
793 
794   // Scope has a different transport
795   Register(remote_endpoint.host_remote()->get(), GURL("wss://www.example.com/"),
796            GURL("https://www.example.com/bar"));
797   EXPECT_EQ(4u, bad_messages_.size());
798 
799   // Script and scope have a different host but match each other
800   Register(remote_endpoint.host_remote()->get(),
801            GURL("https://foo.example.com/"),
802            GURL("https://foo.example.com/bar"));
803   EXPECT_EQ(5u, bad_messages_.size());
804 
805   // Script and scope URLs are invalid
806   Register(remote_endpoint.host_remote()->get(), GURL(), GURL("h@ttps://@"));
807   EXPECT_EQ(6u, bad_messages_.size());
808 }
809 
TEST_F(ServiceWorkerProviderHostTest,Register_BadCharactersShouldFail)810 TEST_F(ServiceWorkerProviderHostTest, Register_BadCharactersShouldFail) {
811   ServiceWorkerRemoteProviderEndpoint remote_endpoint =
812       PrepareServiceWorkerContainerHost(GURL("https://www.example.com"));
813 
814   ASSERT_TRUE(bad_messages_.empty());
815   Register(remote_endpoint.host_remote()->get(),
816            GURL("https://www.example.com/%2f"),
817            GURL("https://www.example.com/"));
818   EXPECT_EQ(1u, bad_messages_.size());
819 
820   Register(remote_endpoint.host_remote()->get(),
821            GURL("https://www.example.com/%2F"),
822            GURL("https://www.example.com/"));
823   EXPECT_EQ(2u, bad_messages_.size());
824 
825   Register(remote_endpoint.host_remote()->get(),
826            GURL("https://www.example.com/"),
827            GURL("https://www.example.com/%2f"));
828   EXPECT_EQ(3u, bad_messages_.size());
829 
830   Register(remote_endpoint.host_remote()->get(),
831            GURL("https://www.example.com/%5c"),
832            GURL("https://www.example.com/"));
833   EXPECT_EQ(4u, bad_messages_.size());
834 
835   Register(remote_endpoint.host_remote()->get(),
836            GURL("https://www.example.com/"),
837            GURL("https://www.example.com/%5c"));
838   EXPECT_EQ(5u, bad_messages_.size());
839 
840   Register(remote_endpoint.host_remote()->get(),
841            GURL("https://www.example.com/"),
842            GURL("https://www.example.com/%5C"));
843   EXPECT_EQ(6u, bad_messages_.size());
844 }
845 
TEST_F(ServiceWorkerProviderHostTest,Register_FileSystemDocumentShouldFail)846 TEST_F(ServiceWorkerProviderHostTest, Register_FileSystemDocumentShouldFail) {
847   ServiceWorkerRemoteProviderEndpoint remote_endpoint =
848       PrepareServiceWorkerContainerHost(
849           GURL("filesystem:https://www.example.com/temporary/a"));
850 
851   ASSERT_TRUE(bad_messages_.empty());
852   Register(remote_endpoint.host_remote()->get(),
853            GURL("filesystem:https://www.example.com/temporary/"),
854            GURL("https://www.example.com/temporary/bar"));
855   EXPECT_EQ(1u, bad_messages_.size());
856 
857   Register(remote_endpoint.host_remote()->get(),
858            GURL("https://www.example.com/temporary/"),
859            GURL("filesystem:https://www.example.com/temporary/bar"));
860   EXPECT_EQ(2u, bad_messages_.size());
861 
862   Register(remote_endpoint.host_remote()->get(),
863            GURL("filesystem:https://www.example.com/temporary/"),
864            GURL("filesystem:https://www.example.com/temporary/bar"));
865   EXPECT_EQ(3u, bad_messages_.size());
866 }
867 
TEST_F(ServiceWorkerProviderHostTest,Register_FileSystemScriptOrScopeShouldFail)868 TEST_F(ServiceWorkerProviderHostTest,
869        Register_FileSystemScriptOrScopeShouldFail) {
870   ServiceWorkerRemoteProviderEndpoint remote_endpoint =
871       PrepareServiceWorkerContainerHost(
872           GURL("https://www.example.com/temporary/"));
873 
874   ASSERT_TRUE(bad_messages_.empty());
875   Register(remote_endpoint.host_remote()->get(),
876            GURL("filesystem:https://www.example.com/temporary/"),
877            GURL("https://www.example.com/temporary/bar"));
878   EXPECT_EQ(1u, bad_messages_.size());
879 
880   Register(remote_endpoint.host_remote()->get(),
881            GURL("https://www.example.com/temporary/"),
882            GURL("filesystem:https://www.example.com/temporary/bar"));
883   EXPECT_EQ(2u, bad_messages_.size());
884 
885   Register(remote_endpoint.host_remote()->get(),
886            GURL("filesystem:https://www.example.com/temporary/"),
887            GURL("filesystem:https://www.example.com/temporary/bar"));
888   EXPECT_EQ(3u, bad_messages_.size());
889 }
890 
TEST_F(ServiceWorkerProviderHostTest,EarlyContextDeletion)891 TEST_F(ServiceWorkerProviderHostTest, EarlyContextDeletion) {
892   ServiceWorkerRemoteProviderEndpoint remote_endpoint =
893       PrepareServiceWorkerContainerHost(GURL("https://www.example.com/foo"));
894 
895   helper_->ShutdownContext();
896 
897   // Let the shutdown reach the simulated IO thread.
898   base::RunLoop().RunUntilIdle();
899 
900   // Because ServiceWorkerContextCore owns ServiceWorkerProviderHost, our
901   // ServiceWorkerProviderHost instance has destroyed.
902   EXPECT_FALSE(remote_endpoint.host_remote()->is_connected());
903 }
904 
TEST_F(ServiceWorkerProviderHostTest,GetRegistration_Success)905 TEST_F(ServiceWorkerProviderHostTest, GetRegistration_Success) {
906   ServiceWorkerRemoteProviderEndpoint remote_endpoint =
907       PrepareServiceWorkerContainerHost(GURL("https://www.example.com/foo"));
908 
909   const GURL kScope("https://www.example.com/");
910   EXPECT_EQ(blink::mojom::ServiceWorkerErrorType::kNone,
911             Register(remote_endpoint.host_remote()->get(), kScope,
912                      GURL("https://www.example.com/sw.js")));
913   blink::mojom::ServiceWorkerRegistrationObjectInfoPtr info;
914   EXPECT_EQ(
915       blink::mojom::ServiceWorkerErrorType::kNone,
916       GetRegistration(remote_endpoint.host_remote()->get(), kScope, &info));
917   ASSERT_TRUE(info);
918   EXPECT_EQ(kScope, info->scope);
919 }
920 
TEST_F(ServiceWorkerProviderHostTest,GetRegistration_NotFoundShouldReturnNull)921 TEST_F(ServiceWorkerProviderHostTest,
922        GetRegistration_NotFoundShouldReturnNull) {
923   ServiceWorkerRemoteProviderEndpoint remote_endpoint =
924       PrepareServiceWorkerContainerHost(GURL("https://www.example.com/foo"));
925 
926   blink::mojom::ServiceWorkerRegistrationObjectInfoPtr info;
927   EXPECT_EQ(blink::mojom::ServiceWorkerErrorType::kNone,
928             GetRegistration(remote_endpoint.host_remote()->get(),
929                             GURL("https://www.example.com/"), &info));
930   EXPECT_FALSE(info);
931 }
932 
TEST_F(ServiceWorkerProviderHostTest,GetRegistration_CrossOriginShouldFail)933 TEST_F(ServiceWorkerProviderHostTest, GetRegistration_CrossOriginShouldFail) {
934   ServiceWorkerRemoteProviderEndpoint remote_endpoint =
935       PrepareServiceWorkerContainerHost(GURL("https://www.example.com/foo"));
936 
937   ASSERT_TRUE(bad_messages_.empty());
938   GetRegistration(remote_endpoint.host_remote()->get(),
939                   GURL("https://foo.example.com/"));
940   EXPECT_EQ(1u, bad_messages_.size());
941 }
942 
TEST_F(ServiceWorkerProviderHostTest,GetRegistration_InvalidScopeShouldFail)943 TEST_F(ServiceWorkerProviderHostTest, GetRegistration_InvalidScopeShouldFail) {
944   ServiceWorkerRemoteProviderEndpoint remote_endpoint =
945       PrepareServiceWorkerContainerHost(GURL("https://www.example.com/foo"));
946 
947   ASSERT_TRUE(bad_messages_.empty());
948   GetRegistration(remote_endpoint.host_remote()->get(), GURL(""));
949   EXPECT_EQ(1u, bad_messages_.size());
950 }
951 
TEST_F(ServiceWorkerProviderHostTest,GetRegistration_NonSecureOriginShouldFail)952 TEST_F(ServiceWorkerProviderHostTest,
953        GetRegistration_NonSecureOriginShouldFail) {
954   ServiceWorkerRemoteProviderEndpoint remote_endpoint =
955       PrepareServiceWorkerContainerHost(GURL("http://www.example.com/foo"));
956 
957   ASSERT_TRUE(bad_messages_.empty());
958   GetRegistration(remote_endpoint.host_remote()->get(),
959                   GURL("http://www.example.com/"));
960   EXPECT_EQ(1u, bad_messages_.size());
961 }
962 
TEST_F(ServiceWorkerProviderHostTest,GetRegistrations_SecureOrigin)963 TEST_F(ServiceWorkerProviderHostTest, GetRegistrations_SecureOrigin) {
964   ServiceWorkerRemoteProviderEndpoint remote_endpoint =
965       PrepareServiceWorkerContainerHost(GURL("https://www.example.com/foo"));
966 
967   EXPECT_EQ(blink::mojom::ServiceWorkerErrorType::kNone,
968             GetRegistrations(remote_endpoint.host_remote()->get()));
969 }
970 
TEST_F(ServiceWorkerProviderHostTest,GetRegistrations_NonSecureOriginShouldFail)971 TEST_F(ServiceWorkerProviderHostTest,
972        GetRegistrations_NonSecureOriginShouldFail) {
973   ServiceWorkerRemoteProviderEndpoint remote_endpoint =
974       PrepareServiceWorkerContainerHost(GURL("http://www.example.com/foo"));
975 
976   ASSERT_TRUE(bad_messages_.empty());
977   GetRegistrations(remote_endpoint.host_remote()->get());
978   EXPECT_EQ(1u, bad_messages_.size());
979 }
980 
981 // Test that a "reserved" (i.e., not execution ready) client is not included
982 // when iterating over client container hosts. If it were, it'd be undesirably
983 // exposed via the Clients API.
TestReservedClientsAreNotExposed(blink::mojom::ServiceWorkerContainerType provider_type,const GURL & url)984 void ServiceWorkerProviderHostTest::TestReservedClientsAreNotExposed(
985     blink::mojom::ServiceWorkerContainerType provider_type,
986     const GURL& url) {
987   {
988     mojo::PendingAssociatedRemote<blink::mojom::ServiceWorkerContainer>
989         client_remote;
990     mojo::PendingAssociatedReceiver<blink::mojom::ServiceWorkerContainerHost>
991         host_receiver;
992     auto provider_info =
993         blink::mojom::ServiceWorkerProviderInfoForClient::New();
994     provider_info->client_receiver =
995         client_remote.InitWithNewEndpointAndPassReceiver();
996     host_receiver =
997         provider_info->host_remote.InitWithNewEndpointAndPassReceiver();
998     base::WeakPtr<ServiceWorkerContainerHost> container_host =
999         ServiceWorkerContainerHost::CreateForWebWorker(
1000             context_->AsWeakPtr(), helper_->mock_render_process_id(),
1001             provider_type, std::move(host_receiver), std::move(client_remote));
1002     container_host->UpdateUrls(url, net::SiteForCookies::FromUrl(url),
1003                                url::Origin::Create(url));
1004     EXPECT_FALSE(CanFindClientContainerHost(container_host.get()));
1005     container_host->CompleteWebWorkerPreparation(
1006         network::CrossOriginEmbedderPolicy());
1007     EXPECT_TRUE(CanFindClientContainerHost(container_host.get()));
1008   }
1009 
1010   {
1011     std::unique_ptr<ServiceWorkerContainerHostAndInfo> host_and_info =
1012         CreateContainerHostAndInfoForWindow(helper_->context()->AsWeakPtr(),
1013                                             /*are_ancestors_secure=*/true);
1014     base::WeakPtr<ServiceWorkerContainerHost> container_host =
1015         std::move(host_and_info->host);
1016     ServiceWorkerRemoteProviderEndpoint remote_endpoint;
1017     remote_endpoint.BindForWindow(std::move(host_and_info->info));
1018 
1019     FinishNavigation(container_host.get());
1020     EXPECT_FALSE(CanFindClientContainerHost(container_host.get()));
1021 
1022     base::RunLoop run_loop;
1023     container_host->AddExecutionReadyCallback(run_loop.QuitClosure());
1024     remote_endpoint.host_remote()->get()->OnExecutionReady();
1025     run_loop.Run();
1026     EXPECT_TRUE(CanFindClientContainerHost(container_host.get()));
1027   }
1028 }
1029 
TEST_F(ServiceWorkerProviderHostTestWithPlzDedicatedWorker,ReservedClientsAreNotExposedToClientsApiForDedicatedWorker)1030 TEST_F(ServiceWorkerProviderHostTestWithPlzDedicatedWorker,
1031        ReservedClientsAreNotExposedToClientsApiForDedicatedWorker) {
1032   ASSERT_TRUE(
1033       base::FeatureList::IsEnabled(blink::features::kPlzDedicatedWorker));
1034   TestReservedClientsAreNotExposed(
1035       blink::mojom::ServiceWorkerContainerType::kForDedicatedWorker,
1036       GURL("https://www.example.com/dedicated_worker.js"));
1037 }
1038 
TEST_F(ServiceWorkerProviderHostTest,ReservedClientsAreNotExposedToClientsApiForSharedWorker)1039 TEST_F(ServiceWorkerProviderHostTest,
1040        ReservedClientsAreNotExposedToClientsApiForSharedWorker) {
1041   TestReservedClientsAreNotExposed(
1042       blink::mojom::ServiceWorkerContainerType::kForSharedWorker,
1043       GURL("https://www.example.com/shared_worker.js"));
1044 }
1045 
1046 // Tests the client phase transitions for a navigation.
TEST_F(ServiceWorkerProviderHostTest,ClientPhaseForWindow)1047 TEST_F(ServiceWorkerProviderHostTest, ClientPhaseForWindow) {
1048   std::unique_ptr<ServiceWorkerContainerHostAndInfo> host_and_info =
1049       CreateContainerHostAndInfoForWindow(helper_->context()->AsWeakPtr(),
1050                                           /*are_ancestors_secure=*/true);
1051   base::WeakPtr<ServiceWorkerContainerHost> container_host =
1052       std::move(host_and_info->host);
1053   ServiceWorkerRemoteProviderEndpoint remote_endpoint;
1054   remote_endpoint.BindForWindow(std::move(host_and_info->info));
1055   EXPECT_FALSE(container_host->is_response_committed());
1056   EXPECT_FALSE(container_host->is_execution_ready());
1057 
1058   FinishNavigation(container_host.get());
1059   EXPECT_TRUE(container_host->is_response_committed());
1060   EXPECT_FALSE(container_host->is_execution_ready());
1061 
1062   base::RunLoop run_loop;
1063   container_host->AddExecutionReadyCallback(run_loop.QuitClosure());
1064   remote_endpoint.host_remote()->get()->OnExecutionReady();
1065   run_loop.Run();
1066   EXPECT_TRUE(container_host->is_response_committed());
1067   EXPECT_TRUE(container_host->is_execution_ready());
1068 }
1069 
1070 // Tests the client phase transitions for workers.
TestClientPhaseTransition(blink::mojom::ServiceWorkerContainerType provider_type,const GURL & url)1071 void ServiceWorkerProviderHostTest::TestClientPhaseTransition(
1072     blink::mojom::ServiceWorkerContainerType provider_type,
1073     const GURL& url) {
1074   mojo::PendingAssociatedRemote<blink::mojom::ServiceWorkerContainer>
1075       client_remote;
1076   mojo::PendingAssociatedReceiver<blink::mojom::ServiceWorkerContainerHost>
1077       host_receiver;
1078   auto provider_info = blink::mojom::ServiceWorkerProviderInfoForClient::New();
1079   provider_info->client_receiver =
1080       client_remote.InitWithNewEndpointAndPassReceiver();
1081   host_receiver =
1082       provider_info->host_remote.InitWithNewEndpointAndPassReceiver();
1083   base::WeakPtr<ServiceWorkerContainerHost> container_host =
1084       ServiceWorkerContainerHost::CreateForWebWorker(
1085           helper_->context()->AsWeakPtr(), helper_->mock_render_process_id(),
1086           provider_type, std::move(host_receiver), std::move(client_remote));
1087   EXPECT_FALSE(container_host->is_response_committed());
1088   EXPECT_FALSE(container_host->is_execution_ready());
1089 
1090   container_host->UpdateUrls(url, net::SiteForCookies::FromUrl(url),
1091                              url::Origin::Create(url));
1092   container_host->CompleteWebWorkerPreparation(
1093       network::CrossOriginEmbedderPolicy());
1094 
1095   EXPECT_TRUE(container_host->is_response_committed());
1096   EXPECT_TRUE(container_host->is_execution_ready());
1097 }
1098 
TEST_F(ServiceWorkerProviderHostTestWithPlzDedicatedWorker,ClientPhaseForDedicatedWorker)1099 TEST_F(ServiceWorkerProviderHostTestWithPlzDedicatedWorker,
1100        ClientPhaseForDedicatedWorker) {
1101   ASSERT_TRUE(
1102       base::FeatureList::IsEnabled(blink::features::kPlzDedicatedWorker));
1103   TestClientPhaseTransition(
1104       blink::mojom::ServiceWorkerContainerType::kForDedicatedWorker,
1105       GURL("https://www.example.com/dedicated_worker.js"));
1106 }
1107 
TEST_F(ServiceWorkerProviderHostTest,ClientPhaseForSharedWorker)1108 TEST_F(ServiceWorkerProviderHostTest, ClientPhaseForSharedWorker) {
1109   TestClientPhaseTransition(
1110       blink::mojom::ServiceWorkerContainerType::kForSharedWorker,
1111       GURL("https://www.example.com/shared_worker.js"));
1112 }
1113 
1114 // Run tests with BackForwardCache.
1115 class ServiceWorkerProviderHostTestWithBackForwardCache
1116     : public ServiceWorkerProviderHostTest {
1117  public:
ServiceWorkerProviderHostTestWithBackForwardCache()1118   ServiceWorkerProviderHostTestWithBackForwardCache() {
1119     scoped_feature_list_.InitWithFeaturesAndParameters(
1120         {{features::kBackForwardCache, {GetFeatureParams()}},
1121          {features::kServiceWorkerOnUI, {}}},
1122         /*disabled_features=*/{});
1123   }
1124 
1125  protected:
GetFeatureParams()1126   base::FieldTrialParams GetFeatureParams() {
1127     return {{"TimeToLiveInBackForwardCacheInSeconds", "3600"},
1128             {"service_worker_supported", "true"}};
1129   }
1130 
1131  private:
1132   base::test::ScopedFeatureList scoped_feature_list_;
1133 };
1134 
1135 // Test that a client in BackForwardCache is not included
1136 // when iterating over client container hosts. If it were, it'd be undesirably
1137 // exposed via the Clients API.
TestBackForwardCachedClientsAreNotExposed(blink::mojom::ServiceWorkerContainerType provider_type,const GURL & url)1138 void ServiceWorkerProviderHostTest::TestBackForwardCachedClientsAreNotExposed(
1139     blink::mojom::ServiceWorkerContainerType provider_type,
1140     const GURL& url) {
1141   std::unique_ptr<ServiceWorkerProviderHost> provider_host;
1142   {
1143     // Create an active version.
1144     scoped_refptr<ServiceWorkerVersion> version =
1145         base::MakeRefCounted<ServiceWorkerVersion>(
1146             registration1_.get(), url, blink::mojom::ScriptType::kClassic,
1147             1 /* version_id */, helper_->context()->AsWeakPtr());
1148     registration1_->SetActiveVersion(version);
1149 
1150     ServiceWorkerRemoteProviderEndpoint remote_endpoint;
1151     provider_host = CreateProviderHostForServiceWorkerContext(
1152         helper_->mock_render_process_id(), true /* is_parent_frame_secure */,
1153         version.get(), helper_->context()->AsWeakPtr(), &remote_endpoint);
1154     ASSERT_TRUE(provider_host);
1155   }
1156   {
1157     std::unique_ptr<ServiceWorkerContainerHostAndInfo> host_and_info =
1158         CreateContainerHostAndInfoForWindow(helper_->context()->AsWeakPtr(),
1159                                             /*are_ancestors_secure=*/true);
1160     base::WeakPtr<ServiceWorkerContainerHost> container_host =
1161         std::move(host_and_info->host);
1162     ServiceWorkerRemoteProviderEndpoint remote_endpoint;
1163     remote_endpoint.BindForWindow(std::move(host_and_info->info));
1164 
1165     FinishNavigation(container_host.get());
1166     EXPECT_FALSE(CanFindClientContainerHost(container_host.get()));
1167 
1168     base::RunLoop run_loop;
1169     container_host->AddExecutionReadyCallback(run_loop.QuitClosure());
1170     remote_endpoint.host_remote()->get()->OnExecutionReady();
1171     run_loop.Run();
1172     EXPECT_TRUE(CanFindClientContainerHost(container_host.get()));
1173     container_host->EnterBackForwardCacheForTesting();
1174     EXPECT_FALSE(CanFindClientContainerHost(container_host.get()));
1175     container_host->LeaveBackForwardCacheForTesting();
1176     EXPECT_TRUE(CanFindClientContainerHost(container_host.get()));
1177   }
1178 }
1179 
TEST_F(ServiceWorkerProviderHostTestWithBackForwardCache,SkipBackForwardCachedServiceWorker)1180 TEST_F(ServiceWorkerProviderHostTestWithBackForwardCache,
1181        SkipBackForwardCachedServiceWorker) {
1182   ASSERT_TRUE(IsBackForwardCacheEnabled());
1183   ASSERT_TRUE(ServiceWorkerContext::IsServiceWorkerOnUIEnabled());
1184 
1185   TestBackForwardCachedClientsAreNotExposed(
1186       blink::mojom::ServiceWorkerContainerType::kForServiceWorker,
1187       GURL("https://www.example.com/sw.js"));
1188 }
1189 
1190 // Tests that the service worker involved with a navigation (via
1191 // AddServiceWorkerToUpdate) is updated when the host for the navigation is
1192 // destroyed.
TEST_F(ServiceWorkerProviderHostTest,UpdateServiceWorkerOnDestruction)1193 TEST_F(ServiceWorkerProviderHostTest, UpdateServiceWorkerOnDestruction) {
1194   // Make a window.
1195   base::WeakPtr<ServiceWorkerContainerHost> container_host =
1196       CreateContainerHost(GURL("https://www.example.com/example.html"));
1197 
1198   // Make an active version.
1199   auto version1 = base::MakeRefCounted<ServiceWorkerVersion>(
1200       registration1_.get(), GURL("https://www.example.com/sw.js"),
1201       blink::mojom::ScriptType::kClassic, 1 /* version_id */,
1202       helper_->context()->AsWeakPtr());
1203   version1->set_fetch_handler_existence(
1204       ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
1205   version1->SetStatus(ServiceWorkerVersion::ACTIVATED);
1206   registration1_->SetActiveVersion(version1);
1207 
1208   auto version2 = base::MakeRefCounted<ServiceWorkerVersion>(
1209       registration2_.get(), GURL("https://www.example.com/sw.js"),
1210       blink::mojom::ScriptType::kClassic, 2 /* version_id */,
1211       helper_->context()->AsWeakPtr());
1212   version2->set_fetch_handler_existence(
1213       ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
1214   version2->SetStatus(ServiceWorkerVersion::ACTIVATED);
1215   registration2_->SetActiveVersion(version1);
1216 
1217   container_host->AddServiceWorkerToUpdate(version1);
1218   container_host->AddServiceWorkerToUpdate(version2);
1219   ExpectUpdateIsNotScheduled(version1.get());
1220   ExpectUpdateIsNotScheduled(version2.get());
1221 
1222   // Destroy the container host.
1223   ASSERT_TRUE(remote_endpoints_.back().host_remote()->is_bound());
1224   remote_endpoints_.back().host_remote()->reset();
1225   base::RunLoop().RunUntilIdle();
1226 
1227   // The container host's destructor should have scheduled the update.
1228   ExpectUpdateIsScheduled(version1.get());
1229   ExpectUpdateIsScheduled(version2.get());
1230 }
1231 
1232 // Tests that the service worker involved with a navigation is updated when the
1233 // host receives a HintToUpdateServiceWorker message.
TEST_F(ServiceWorkerProviderHostTest,HintToUpdateServiceWorker)1234 TEST_F(ServiceWorkerProviderHostTest, HintToUpdateServiceWorker) {
1235   // Make an active version.
1236   auto version1 = base::MakeRefCounted<ServiceWorkerVersion>(
1237       registration1_.get(), GURL("https://www.example.com/sw.js"),
1238       blink::mojom::ScriptType::kClassic, 1 /* version_id */,
1239       helper_->context()->AsWeakPtr());
1240   version1->set_fetch_handler_existence(
1241       ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
1242   version1->SetStatus(ServiceWorkerVersion::ACTIVATED);
1243   registration1_->SetActiveVersion(version1);
1244 
1245   // Make a window.
1246   base::WeakPtr<ServiceWorkerContainerHost> container_host =
1247       CreateContainerHost(GURL("https://www.example.com/example.html"));
1248 
1249   // Mark the service worker as needing update. Update should not be scheduled
1250   // yet.
1251   container_host->AddServiceWorkerToUpdate(version1);
1252   ExpectUpdateIsNotScheduled(version1.get());
1253   EXPECT_TRUE(HasVersionToUpdate(container_host.get()));
1254 
1255   // Send the hint from the renderer. Update should be scheduled.
1256   mojo::AssociatedRemote<blink::mojom::ServiceWorkerContainerHost>*
1257       host_remote = remote_endpoints_.back().host_remote();
1258   (*host_remote)->HintToUpdateServiceWorker();
1259   base::RunLoop().RunUntilIdle();
1260   ExpectUpdateIsScheduled(version1.get());
1261   EXPECT_FALSE(HasVersionToUpdate(container_host.get()));
1262 }
1263 
1264 // Tests that the host receives a HintToUpdateServiceWorker message but
1265 // there was no service worker at main resource request time. This
1266 // can happen due to claim().
TEST_F(ServiceWorkerProviderHostTest,HintToUpdateServiceWorkerButNoVersionToUpdate)1267 TEST_F(ServiceWorkerProviderHostTest,
1268        HintToUpdateServiceWorkerButNoVersionToUpdate) {
1269   // Make a window.
1270   base::WeakPtr<ServiceWorkerContainerHost> container_host =
1271       CreateContainerHost(GURL("https://www.example.com/example.html"));
1272 
1273   // Make an active version.
1274   auto version1 = base::MakeRefCounted<ServiceWorkerVersion>(
1275       registration1_.get(), GURL("https://www.example.com/sw.js"),
1276       blink::mojom::ScriptType::kClassic, 1 /* version_id */,
1277       helper_->context()->AsWeakPtr());
1278   version1->set_fetch_handler_existence(
1279       ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
1280   version1->SetStatus(ServiceWorkerVersion::ACTIVATED);
1281   registration1_->SetActiveVersion(version1);
1282 
1283   // Pretend the registration gets associated after the main
1284   // resource request, so AddServiceWorkerToUpdate() is not called.
1285 
1286   ExpectUpdateIsNotScheduled(version1.get());
1287   EXPECT_FALSE(HasVersionToUpdate(container_host.get()));
1288 
1289   // Send the hint from the renderer. Update should not be scheduled, since
1290   // AddServiceWorkerToUpdate() was not called.
1291   mojo::AssociatedRemote<blink::mojom::ServiceWorkerContainerHost>*
1292       host_remote = remote_endpoints_.back().host_remote();
1293   (*host_remote)->HintToUpdateServiceWorker();
1294   base::RunLoop().RunUntilIdle();
1295   ExpectUpdateIsNotScheduled(version1.get());
1296   EXPECT_FALSE(HasVersionToUpdate(container_host.get()));
1297 }
1298 
TEST_F(ServiceWorkerProviderHostTest,HintToUpdateServiceWorkerMultiple)1299 TEST_F(ServiceWorkerProviderHostTest, HintToUpdateServiceWorkerMultiple) {
1300   // Make active versions.
1301   auto version1 = base::MakeRefCounted<ServiceWorkerVersion>(
1302       registration1_.get(), GURL("https://www.example.com/sw.js"),
1303       blink::mojom::ScriptType::kClassic, 1 /* version_id */,
1304       helper_->context()->AsWeakPtr());
1305   version1->set_fetch_handler_existence(
1306       ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
1307   version1->SetStatus(ServiceWorkerVersion::ACTIVATED);
1308   registration1_->SetActiveVersion(version1);
1309 
1310   auto version2 = base::MakeRefCounted<ServiceWorkerVersion>(
1311       registration2_.get(), GURL("https://www.example.com/sw.js"),
1312       blink::mojom::ScriptType::kClassic, 2 /* version_id */,
1313       helper_->context()->AsWeakPtr());
1314   version2->set_fetch_handler_existence(
1315       ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
1316   version2->SetStatus(ServiceWorkerVersion::ACTIVATED);
1317   registration2_->SetActiveVersion(version1);
1318 
1319   auto version3 = base::MakeRefCounted<ServiceWorkerVersion>(
1320       registration3_.get(), GURL("https://other.example.com/sw.js"),
1321       blink::mojom::ScriptType::kClassic, 3 /* version_id */,
1322       helper_->context()->AsWeakPtr());
1323   version3->set_fetch_handler_existence(
1324       ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
1325   version3->SetStatus(ServiceWorkerVersion::ACTIVATED);
1326   registration3_->SetActiveVersion(version1);
1327 
1328   // Make a window.
1329   base::WeakPtr<ServiceWorkerContainerHost> container_host =
1330       CreateContainerHost(GURL("https://www.example.com/example.html"));
1331 
1332   // Mark the service worker as needing update. Update should not be scheduled
1333   // yet.
1334   container_host->AddServiceWorkerToUpdate(version1);
1335   container_host->AddServiceWorkerToUpdate(version2);
1336   container_host->AddServiceWorkerToUpdate(version3);
1337   ExpectUpdateIsNotScheduled(version1.get());
1338   ExpectUpdateIsNotScheduled(version2.get());
1339   ExpectUpdateIsNotScheduled(version3.get());
1340   EXPECT_TRUE(HasVersionToUpdate(container_host.get()));
1341 
1342   // Pretend another page also used version3.
1343   version3->IncrementPendingUpdateHintCount();
1344 
1345   // Send the hint from the renderer. Update should be scheduled except for
1346   // |version3| as it's being used by another page.
1347   mojo::AssociatedRemote<blink::mojom::ServiceWorkerContainerHost>*
1348       host_remote = remote_endpoints_.back().host_remote();
1349   (*host_remote)->HintToUpdateServiceWorker();
1350   base::RunLoop().RunUntilIdle();
1351   ExpectUpdateIsScheduled(version1.get());
1352   ExpectUpdateIsScheduled(version2.get());
1353   ExpectUpdateIsNotScheduled(version3.get());
1354   EXPECT_FALSE(HasVersionToUpdate(container_host.get()));
1355 
1356   // Pretend the other page also finished for version3.
1357   version3->DecrementPendingUpdateHintCount();
1358   ExpectUpdateIsScheduled(version3.get());
1359 }
1360 
1361 }  // namespace content
1362