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