OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/service_worker/service_worker_dispatcher_host.h" | 5 #include "content/browser/service_worker/service_worker_dispatcher_host.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
11 #include "base/files/file_path.h" | 11 #include "base/files/file_path.h" |
12 #include "base/run_loop.h" | 12 #include "base/run_loop.h" |
13 #include "content/browser/browser_thread_impl.h" | 13 #include "content/browser/browser_thread_impl.h" |
| 14 #include "content/browser/message_port_service.h" |
14 #include "content/browser/service_worker/embedded_worker_instance.h" | 15 #include "content/browser/service_worker/embedded_worker_instance.h" |
15 #include "content/browser/service_worker/embedded_worker_registry.h" | 16 #include "content/browser/service_worker/embedded_worker_registry.h" |
16 #include "content/browser/service_worker/embedded_worker_test_helper.h" | 17 #include "content/browser/service_worker/embedded_worker_test_helper.h" |
17 #include "content/browser/service_worker/service_worker_context_core.h" | 18 #include "content/browser/service_worker/service_worker_context_core.h" |
18 #include "content/browser/service_worker/service_worker_context_wrapper.h" | 19 #include "content/browser/service_worker/service_worker_context_wrapper.h" |
| 20 #include "content/browser/service_worker/service_worker_handle.h" |
19 #include "content/common/service_worker/embedded_worker_messages.h" | 21 #include "content/common/service_worker/embedded_worker_messages.h" |
20 #include "content/common/service_worker/service_worker_messages.h" | 22 #include "content/common/service_worker/service_worker_messages.h" |
21 #include "content/public/common/content_switches.h" | 23 #include "content/public/common/content_switches.h" |
22 #include "content/public/test/mock_resource_context.h" | 24 #include "content/public/test/mock_resource_context.h" |
23 #include "content/public/test/test_browser_thread_bundle.h" | 25 #include "content/public/test/test_browser_thread_bundle.h" |
24 #include "content/test/test_content_browser_client.h" | 26 #include "content/test/test_content_browser_client.h" |
25 #include "testing/gtest/include/gtest/gtest.h" | 27 #include "testing/gtest/include/gtest/gtest.h" |
26 | 28 |
27 namespace content { | 29 namespace content { |
28 | 30 |
29 namespace { | 31 namespace { |
30 | 32 |
31 static void SaveStatusCallback(bool* called, | 33 static void SaveStatusCallback(bool* called, |
32 ServiceWorkerStatusCode* out, | 34 ServiceWorkerStatusCode* out, |
33 ServiceWorkerStatusCode status) { | 35 ServiceWorkerStatusCode status) { |
34 *called = true; | 36 *called = true; |
35 *out = status; | 37 *out = status; |
36 } | 38 } |
37 | 39 |
| 40 void SetUpDummyMessagePort(std::vector<TransferredMessagePort>* ports) { |
| 41 int port_id = -1; |
| 42 MessagePortService::GetInstance()->Create(MSG_ROUTING_NONE, nullptr, |
| 43 &port_id); |
| 44 TransferredMessagePort dummy_port; |
| 45 dummy_port.id = port_id; |
| 46 ports->push_back(dummy_port); |
38 } | 47 } |
39 | 48 |
| 49 } // namespace |
| 50 |
40 static const int kRenderFrameId = 1; | 51 static const int kRenderFrameId = 1; |
41 | 52 |
42 class TestingServiceWorkerDispatcherHost : public ServiceWorkerDispatcherHost { | 53 class TestingServiceWorkerDispatcherHost : public ServiceWorkerDispatcherHost { |
43 public: | 54 public: |
44 TestingServiceWorkerDispatcherHost( | 55 TestingServiceWorkerDispatcherHost( |
45 int process_id, | 56 int process_id, |
46 ServiceWorkerContextWrapper* context_wrapper, | 57 ServiceWorkerContextWrapper* context_wrapper, |
47 ResourceContext* resource_context, | 58 ResourceContext* resource_context, |
48 EmbeddedWorkerTestHelper* helper) | 59 EmbeddedWorkerTestHelper* helper) |
49 : ServiceWorkerDispatcherHost(process_id, NULL, resource_context), | 60 : ServiceWorkerDispatcherHost(process_id, NULL, resource_context), |
50 bad_messages_received_count_(0), | 61 bad_messages_received_count_(0), |
51 helper_(helper) { | 62 helper_(helper) { |
52 Init(context_wrapper); | 63 Init(context_wrapper); |
53 } | 64 } |
54 | 65 |
55 bool Send(IPC::Message* message) override { return helper_->Send(message); } | 66 bool Send(IPC::Message* message) override { return helper_->Send(message); } |
56 | 67 |
57 IPC::TestSink* ipc_sink() { return helper_->ipc_sink(); } | 68 IPC::TestSink* ipc_sink() { return helper_->ipc_sink(); } |
58 | 69 |
59 void ShutdownForBadMessage() override { ++bad_messages_received_count_; } | 70 void ShutdownForBadMessage() override { ++bad_messages_received_count_; } |
60 | 71 |
61 int bad_messages_received_count_; | 72 int bad_messages_received_count_; |
62 | 73 |
63 protected: | 74 protected: |
64 EmbeddedWorkerTestHelper* helper_; | 75 EmbeddedWorkerTestHelper* helper_; |
65 ~TestingServiceWorkerDispatcherHost() override {} | 76 ~TestingServiceWorkerDispatcherHost() override {} |
66 }; | 77 }; |
67 | 78 |
| 79 class FailToStartWorkerTestHelper : public EmbeddedWorkerTestHelper { |
| 80 public: |
| 81 FailToStartWorkerTestHelper() : EmbeddedWorkerTestHelper(base::FilePath()) {} |
| 82 |
| 83 void OnStartWorker(int embedded_worker_id, |
| 84 int64_t service_worker_version_id, |
| 85 const GURL& scope, |
| 86 const GURL& script_url, |
| 87 bool pause_after_download) override { |
| 88 EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id); |
| 89 registry()->OnWorkerStopped(worker->process_id(), embedded_worker_id); |
| 90 } |
| 91 }; |
| 92 |
68 class ServiceWorkerDispatcherHostTest : public testing::Test { | 93 class ServiceWorkerDispatcherHostTest : public testing::Test { |
69 protected: | 94 protected: |
70 ServiceWorkerDispatcherHostTest() | 95 ServiceWorkerDispatcherHostTest() |
71 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {} | 96 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {} |
72 | 97 |
73 void SetUp() override { | 98 void SetUp() override { |
74 helper_.reset(new EmbeddedWorkerTestHelper(base::FilePath())); | 99 Initialize(make_scoped_ptr(new EmbeddedWorkerTestHelper(base::FilePath()))); |
75 dispatcher_host_ = new TestingServiceWorkerDispatcherHost( | |
76 helper_->mock_render_process_id(), context_wrapper(), | |
77 &resource_context_, helper_.get()); | |
78 } | 100 } |
79 | 101 |
80 void TearDown() override { helper_.reset(); } | 102 void TearDown() override { helper_.reset(); } |
81 | 103 |
82 ServiceWorkerContextCore* context() { return helper_->context(); } | 104 ServiceWorkerContextCore* context() { return helper_->context(); } |
83 ServiceWorkerContextWrapper* context_wrapper() { | 105 ServiceWorkerContextWrapper* context_wrapper() { |
84 return helper_->context_wrapper(); | 106 return helper_->context_wrapper(); |
85 } | 107 } |
86 | 108 |
| 109 void Initialize(scoped_ptr<EmbeddedWorkerTestHelper> helper) { |
| 110 helper_.reset(helper.release()); |
| 111 dispatcher_host_ = new TestingServiceWorkerDispatcherHost( |
| 112 helper_->mock_render_process_id(), context_wrapper(), |
| 113 &resource_context_, helper_.get()); |
| 114 } |
| 115 |
87 void SendRegister(int64_t provider_id, GURL pattern, GURL worker_url) { | 116 void SendRegister(int64_t provider_id, GURL pattern, GURL worker_url) { |
88 dispatcher_host_->OnMessageReceived( | 117 dispatcher_host_->OnMessageReceived( |
89 ServiceWorkerHostMsg_RegisterServiceWorker( | 118 ServiceWorkerHostMsg_RegisterServiceWorker( |
90 -1, -1, provider_id, pattern, worker_url)); | 119 -1, -1, provider_id, pattern, worker_url)); |
91 base::RunLoop().RunUntilIdle(); | 120 base::RunLoop().RunUntilIdle(); |
92 } | 121 } |
93 | 122 |
94 void Register(int64_t provider_id, | 123 void Register(int64_t provider_id, |
95 GURL pattern, | 124 GURL pattern, |
96 GURL worker_url, | 125 GURL worker_url, |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
139 base::RunLoop().RunUntilIdle(); | 168 base::RunLoop().RunUntilIdle(); |
140 } | 169 } |
141 | 170 |
142 void GetRegistrations(int64_t provider_id, uint32_t expected_message) { | 171 void GetRegistrations(int64_t provider_id, uint32_t expected_message) { |
143 SendGetRegistrations(provider_id); | 172 SendGetRegistrations(provider_id); |
144 EXPECT_TRUE(dispatcher_host_->ipc_sink()->GetUniqueMessageMatching( | 173 EXPECT_TRUE(dispatcher_host_->ipc_sink()->GetUniqueMessageMatching( |
145 expected_message)); | 174 expected_message)); |
146 dispatcher_host_->ipc_sink()->ClearMessages(); | 175 dispatcher_host_->ipc_sink()->ClearMessages(); |
147 } | 176 } |
148 | 177 |
| 178 void DispatchExtendableMessageEvent( |
| 179 scoped_refptr<ServiceWorkerVersion> worker, |
| 180 const base::string16& message, |
| 181 const url::Origin& source_origin, |
| 182 const std::vector<TransferredMessagePort>& sent_message_ports, |
| 183 ServiceWorkerProviderHost* sender_provider_host, |
| 184 const ServiceWorkerDispatcherHost::StatusCallback& callback) { |
| 185 dispatcher_host_->DispatchExtendableMessageEvent( |
| 186 std::move(worker), message, source_origin, sent_message_ports, |
| 187 sender_provider_host, callback); |
| 188 } |
| 189 |
149 ServiceWorkerProviderHost* CreateServiceWorkerProviderHost(int provider_id) { | 190 ServiceWorkerProviderHost* CreateServiceWorkerProviderHost(int provider_id) { |
150 return new ServiceWorkerProviderHost( | 191 return new ServiceWorkerProviderHost( |
151 helper_->mock_render_process_id(), kRenderFrameId, provider_id, | 192 helper_->mock_render_process_id(), kRenderFrameId, provider_id, |
152 SERVICE_WORKER_PROVIDER_FOR_WINDOW, context()->AsWeakPtr(), | 193 SERVICE_WORKER_PROVIDER_FOR_WINDOW, context()->AsWeakPtr(), |
153 dispatcher_host_.get()); | 194 dispatcher_host_.get()); |
154 } | 195 } |
155 | 196 |
156 | |
157 TestBrowserThreadBundle browser_thread_bundle_; | 197 TestBrowserThreadBundle browser_thread_bundle_; |
158 content::MockResourceContext resource_context_; | 198 content::MockResourceContext resource_context_; |
159 scoped_ptr<EmbeddedWorkerTestHelper> helper_; | 199 scoped_ptr<EmbeddedWorkerTestHelper> helper_; |
160 scoped_refptr<TestingServiceWorkerDispatcherHost> dispatcher_host_; | 200 scoped_refptr<TestingServiceWorkerDispatcherHost> dispatcher_host_; |
161 }; | 201 }; |
162 | 202 |
163 class ServiceWorkerTestContentBrowserClient : public TestContentBrowserClient { | 203 class ServiceWorkerTestContentBrowserClient : public TestContentBrowserClient { |
164 public: | 204 public: |
165 ServiceWorkerTestContentBrowserClient() {} | 205 ServiceWorkerTestContentBrowserClient() {} |
166 bool AllowServiceWorker(const GURL& scope, | 206 bool AllowServiceWorker(const GURL& scope, |
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
589 process_id, context_wrapper(), &resource_context_, helper_.get())); | 629 process_id, context_wrapper(), &resource_context_, helper_.get())); |
590 | 630 |
591 // To show the new dispatcher can operate, simulate provider creation. Since | 631 // To show the new dispatcher can operate, simulate provider creation. Since |
592 // the old dispatcher cleaned up the old provider host, the new one won't | 632 // the old dispatcher cleaned up the old provider host, the new one won't |
593 // complain. | 633 // complain. |
594 new_dispatcher_host->OnMessageReceived(ServiceWorkerHostMsg_ProviderCreated( | 634 new_dispatcher_host->OnMessageReceived(ServiceWorkerHostMsg_ProviderCreated( |
595 kProviderId, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_WINDOW)); | 635 kProviderId, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_WINDOW)); |
596 EXPECT_EQ(0, new_dispatcher_host->bad_messages_received_count_); | 636 EXPECT_EQ(0, new_dispatcher_host->bad_messages_received_count_); |
597 } | 637 } |
598 | 638 |
| 639 TEST_F(ServiceWorkerDispatcherHostTest, DispatchExtendableMessageEvent) { |
| 640 GURL pattern = GURL("http://www.example.com/"); |
| 641 GURL scope = GURL("http://www.example.com/service_worker.js"); |
| 642 int process_id = helper_->mock_render_process_id(); |
| 643 |
| 644 // Add a provider for a service worker to send a message. |
| 645 const int64_t kProviderId = 99; |
| 646 dispatcher_host_->OnMessageReceived(ServiceWorkerHostMsg_ProviderCreated( |
| 647 kProviderId, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_CONTROLLER)); |
| 648 helper_->SimulateAddProcessToPattern(pattern, process_id); |
| 649 ServiceWorkerProviderHost* sender_provider_host = |
| 650 context()->GetProviderHost(process_id, kProviderId); |
| 651 |
| 652 // Set up a registration and service worker to receive a message. |
| 653 scoped_refptr<ServiceWorkerRegistration> registration( |
| 654 new ServiceWorkerRegistration(pattern, 1L, |
| 655 helper_->context()->AsWeakPtr())); |
| 656 scoped_refptr<ServiceWorkerVersion> version(new ServiceWorkerVersion( |
| 657 registration.get(), scope, 1L, helper_->context()->AsWeakPtr())); |
| 658 std::vector<ServiceWorkerDatabase::ResourceRecord> records; |
| 659 records.push_back( |
| 660 ServiceWorkerDatabase::ResourceRecord(10, version->script_url(), 100)); |
| 661 version->script_cache_map()->SetResources(records); |
| 662 |
| 663 // Make the registration findable via storage functions. |
| 664 helper_->context()->storage()->LazyInitialize(base::Bind(&base::DoNothing)); |
| 665 base::RunLoop().RunUntilIdle(); |
| 666 bool called = false; |
| 667 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE; |
| 668 helper_->context()->storage()->StoreRegistration( |
| 669 registration.get(), version.get(), |
| 670 base::Bind(&SaveStatusCallback, &called, &status)); |
| 671 base::RunLoop().RunUntilIdle(); |
| 672 EXPECT_TRUE(called); |
| 673 ASSERT_EQ(SERVICE_WORKER_OK, status); |
| 674 |
| 675 // Set the running hosted version so that we can retrieve a valid service |
| 676 // worker object information for the source attribute of the message event. |
| 677 sender_provider_host->running_hosted_version_ = version; |
| 678 |
| 679 // Set aside the initial refcount of the worker handle. |
| 680 sender_provider_host->GetOrCreateServiceWorkerHandle(version.get()); |
| 681 ServiceWorkerHandle* sender_worker_handle = |
| 682 dispatcher_host_->FindServiceWorkerHandle( |
| 683 sender_provider_host->provider_id(), version->version_id()); |
| 684 const int ref_count = sender_worker_handle->ref_count(); |
| 685 |
| 686 // Dispatch ExtendableMessageEvent. |
| 687 std::vector<TransferredMessagePort> ports; |
| 688 SetUpDummyMessagePort(&ports); |
| 689 called = false; |
| 690 status = SERVICE_WORKER_ERROR_MAX_VALUE; |
| 691 DispatchExtendableMessageEvent( |
| 692 version, base::string16(), url::Origin(version->scope().GetOrigin()), |
| 693 ports, sender_provider_host, |
| 694 base::Bind(&SaveStatusCallback, &called, &status)); |
| 695 for (TransferredMessagePort port : ports) |
| 696 EXPECT_TRUE(MessagePortService::GetInstance()->AreMessagesHeld(port.id)); |
| 697 EXPECT_EQ(ref_count + 1, sender_worker_handle->ref_count()); |
| 698 base::RunLoop().RunUntilIdle(); |
| 699 EXPECT_TRUE(called); |
| 700 EXPECT_EQ(SERVICE_WORKER_OK, status); |
| 701 |
| 702 // Messages should be held until ports are created at the destination. |
| 703 for (TransferredMessagePort port : ports) |
| 704 EXPECT_TRUE(MessagePortService::GetInstance()->AreMessagesHeld(port.id)); |
| 705 |
| 706 EXPECT_EQ(ref_count + 1, sender_worker_handle->ref_count()); |
| 707 } |
| 708 |
| 709 TEST_F(ServiceWorkerDispatcherHostTest, DispatchExtendableMessageEvent_Fail) { |
| 710 Initialize(make_scoped_ptr(new FailToStartWorkerTestHelper)); |
| 711 |
| 712 GURL pattern = GURL("http://www.example.com/"); |
| 713 GURL scope = GURL("http://www.example.com/service_worker.js"); |
| 714 int process_id = helper_->mock_render_process_id(); |
| 715 |
| 716 // Add a provider for a service worker to send a message. |
| 717 const int64_t kProviderId = 99; |
| 718 dispatcher_host_->OnMessageReceived(ServiceWorkerHostMsg_ProviderCreated( |
| 719 kProviderId, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_CONTROLLER)); |
| 720 helper_->SimulateAddProcessToPattern(pattern, process_id); |
| 721 ServiceWorkerProviderHost* sender_provider_host = |
| 722 context()->GetProviderHost(process_id, kProviderId); |
| 723 |
| 724 // Set up a registration and service worker to receive a message. |
| 725 scoped_refptr<ServiceWorkerRegistration> registration( |
| 726 new ServiceWorkerRegistration(pattern, 1L, |
| 727 helper_->context()->AsWeakPtr())); |
| 728 scoped_refptr<ServiceWorkerVersion> version(new ServiceWorkerVersion( |
| 729 registration.get(), scope, 1L, helper_->context()->AsWeakPtr())); |
| 730 std::vector<ServiceWorkerDatabase::ResourceRecord> records; |
| 731 records.push_back( |
| 732 ServiceWorkerDatabase::ResourceRecord(10, version->script_url(), 100)); |
| 733 version->script_cache_map()->SetResources(records); |
| 734 |
| 735 // Make the registration findable via storage functions. |
| 736 helper_->context()->storage()->LazyInitialize(base::Bind(&base::DoNothing)); |
| 737 base::RunLoop().RunUntilIdle(); |
| 738 bool called = false; |
| 739 ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE; |
| 740 helper_->context()->storage()->StoreRegistration( |
| 741 registration.get(), version.get(), |
| 742 base::Bind(&SaveStatusCallback, &called, &status)); |
| 743 base::RunLoop().RunUntilIdle(); |
| 744 EXPECT_TRUE(called); |
| 745 ASSERT_EQ(SERVICE_WORKER_OK, status); |
| 746 |
| 747 // Set the running hosted version so that we can retrieve a valid service |
| 748 // worker object information for the source attribute of the message event. |
| 749 sender_provider_host->running_hosted_version_ = version; |
| 750 |
| 751 // Set aside the initial refcount of the worker handle. |
| 752 sender_provider_host->GetOrCreateServiceWorkerHandle(version.get()); |
| 753 ServiceWorkerHandle* sender_worker_handle = |
| 754 dispatcher_host_->FindServiceWorkerHandle( |
| 755 sender_provider_host->provider_id(), version->version_id()); |
| 756 const int ref_count = sender_worker_handle->ref_count(); |
| 757 |
| 758 // Try to dispatch ExtendableMessageEvent. This should fail to start the |
| 759 // worker and to dispatch the event. |
| 760 std::vector<TransferredMessagePort> ports; |
| 761 SetUpDummyMessagePort(&ports); |
| 762 called = false; |
| 763 status = SERVICE_WORKER_ERROR_MAX_VALUE; |
| 764 DispatchExtendableMessageEvent( |
| 765 version, base::string16(), url::Origin(version->scope().GetOrigin()), |
| 766 ports, sender_provider_host, |
| 767 base::Bind(&SaveStatusCallback, &called, &status)); |
| 768 for (TransferredMessagePort port : ports) |
| 769 EXPECT_TRUE(MessagePortService::GetInstance()->AreMessagesHeld(port.id)); |
| 770 EXPECT_EQ(ref_count + 1, sender_worker_handle->ref_count()); |
| 771 base::RunLoop().RunUntilIdle(); |
| 772 EXPECT_TRUE(called); |
| 773 EXPECT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, status); |
| 774 |
| 775 // The error callback should clean up the ports and handle. |
| 776 for (TransferredMessagePort port : ports) |
| 777 EXPECT_FALSE(MessagePortService::GetInstance()->AreMessagesHeld(port.id)); |
| 778 EXPECT_EQ(ref_count, sender_worker_handle->ref_count()); |
| 779 } |
| 780 |
599 } // namespace content | 781 } // namespace content |
OLD | NEW |