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 3// found in the LICENSE file. 4 5#include "content/browser/service_worker/service_worker_dispatcher_host.h" 6 7#include "base/command_line.h" 8#include "base/files/file_path.h" 9#include "base/run_loop.h" 10#include "content/browser/browser_thread_impl.h" 11#include "content/browser/service_worker/embedded_worker_instance.h" 12#include "content/browser/service_worker/embedded_worker_registry.h" 13#include "content/browser/service_worker/embedded_worker_test_helper.h" 14#include "content/browser/service_worker/service_worker_context_core.h" 15#include "content/browser/service_worker/service_worker_context_wrapper.h" 16#include "content/common/service_worker/embedded_worker_messages.h" 17#include "content/common/service_worker/service_worker_messages.h" 18#include "content/public/common/content_switches.h" 19#include "content/public/test/test_browser_thread_bundle.h" 20#include "testing/gtest/include/gtest/gtest.h" 21 22namespace content { 23 24static const int kRenderProcessId = 1; 25 26class TestingServiceWorkerDispatcherHost : public ServiceWorkerDispatcherHost { 27 public: 28 TestingServiceWorkerDispatcherHost( 29 int process_id, 30 ServiceWorkerContextWrapper* context_wrapper, 31 EmbeddedWorkerTestHelper* helper) 32 : ServiceWorkerDispatcherHost(process_id, NULL), 33 bad_messages_received_count_(0), 34 helper_(helper) { 35 Init(context_wrapper); 36 } 37 38 virtual bool Send(IPC::Message* message) OVERRIDE { 39 return helper_->Send(message); 40 } 41 42 IPC::TestSink* ipc_sink() { return helper_->ipc_sink(); } 43 44 virtual void BadMessageReceived() OVERRIDE { 45 ++bad_messages_received_count_; 46 } 47 48 int bad_messages_received_count_; 49 50 protected: 51 EmbeddedWorkerTestHelper* helper_; 52 virtual ~TestingServiceWorkerDispatcherHost() {} 53}; 54 55class ServiceWorkerDispatcherHostTest : public testing::Test { 56 protected: 57 ServiceWorkerDispatcherHostTest() 58 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {} 59 60 virtual void SetUp() { 61 helper_.reset(new EmbeddedWorkerTestHelper(kRenderProcessId)); 62 dispatcher_host_ = new TestingServiceWorkerDispatcherHost( 63 kRenderProcessId, context_wrapper(), helper_.get()); 64 } 65 66 virtual void TearDown() { 67 helper_.reset(); 68 } 69 70 ServiceWorkerContextCore* context() { return helper_->context(); } 71 ServiceWorkerContextWrapper* context_wrapper() { 72 return helper_->context_wrapper(); 73 } 74 75 void SendRegister(int64 provider_id, GURL pattern, GURL worker_url) { 76 dispatcher_host_->OnMessageReceived( 77 ServiceWorkerHostMsg_RegisterServiceWorker( 78 -1, -1, provider_id, pattern, worker_url)); 79 base::RunLoop().RunUntilIdle(); 80 } 81 82 void Register(int64 provider_id, 83 GURL pattern, 84 GURL worker_url, 85 uint32 expected_message) { 86 SendRegister(provider_id, pattern, worker_url); 87 EXPECT_TRUE(dispatcher_host_->ipc_sink()->GetUniqueMessageMatching( 88 expected_message)); 89 dispatcher_host_->ipc_sink()->ClearMessages(); 90 } 91 92 void SendUnregister(int64 provider_id, GURL pattern) { 93 dispatcher_host_->OnMessageReceived( 94 ServiceWorkerHostMsg_UnregisterServiceWorker( 95 -1, -1, provider_id, pattern)); 96 base::RunLoop().RunUntilIdle(); 97 } 98 99 void Unregister(int64 provider_id, GURL pattern, uint32 expected_message) { 100 SendUnregister(provider_id, pattern); 101 EXPECT_TRUE(dispatcher_host_->ipc_sink()->GetUniqueMessageMatching( 102 expected_message)); 103 dispatcher_host_->ipc_sink()->ClearMessages(); 104 } 105 106 void SendGetRegistration(int64 provider_id, GURL document_url) { 107 dispatcher_host_->OnMessageReceived( 108 ServiceWorkerHostMsg_GetRegistration( 109 -1, -1, provider_id, document_url)); 110 base::RunLoop().RunUntilIdle(); 111 } 112 113 void GetRegistration(int64 provider_id, 114 GURL document_url, 115 uint32 expected_message) { 116 SendGetRegistration(provider_id, document_url); 117 EXPECT_TRUE(dispatcher_host_->ipc_sink()->GetUniqueMessageMatching( 118 expected_message)); 119 dispatcher_host_->ipc_sink()->ClearMessages(); 120 } 121 122 TestBrowserThreadBundle browser_thread_bundle_; 123 scoped_ptr<EmbeddedWorkerTestHelper> helper_; 124 scoped_refptr<TestingServiceWorkerDispatcherHost> dispatcher_host_; 125}; 126 127TEST_F(ServiceWorkerDispatcherHostTest, Register_SameOrigin) { 128 const int64 kProviderId = 99; // Dummy value 129 scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost( 130 kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL)); 131 host->SetDocumentUrl(GURL("https://www.example.com/foo")); 132 base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr(); 133 context()->AddProviderHost(host.Pass()); 134 135 Register(kProviderId, 136 GURL("https://www.example.com/"), 137 GURL("https://www.example.com/bar"), 138 ServiceWorkerMsg_ServiceWorkerRegistered::ID); 139} 140 141TEST_F(ServiceWorkerDispatcherHostTest, Register_CrossOrigin) { 142 const int64 kProviderId = 99; // Dummy value 143 scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost( 144 kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL)); 145 host->SetDocumentUrl(GURL("https://www.example.com/foo")); 146 base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr(); 147 context()->AddProviderHost(host.Pass()); 148 149 // Script has a different host 150 SendRegister(kProviderId, 151 GURL("https://www.example.com/"), 152 GURL("https://foo.example.com/bar")); 153 EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_); 154 155 // Scope has a different host 156 SendRegister(kProviderId, 157 GURL("https://foo.example.com/"), 158 GURL("https://www.example.com/bar")); 159 EXPECT_EQ(2, dispatcher_host_->bad_messages_received_count_); 160 161 // Script has a different port 162 SendRegister(kProviderId, 163 GURL("https://www.example.com/"), 164 GURL("https://www.example.com:8080/bar")); 165 EXPECT_EQ(3, dispatcher_host_->bad_messages_received_count_); 166 167 // Scope has a different transport 168 SendRegister(kProviderId, 169 GURL("wss://www.example.com/"), 170 GURL("https://www.example.com/bar")); 171 EXPECT_EQ(4, dispatcher_host_->bad_messages_received_count_); 172 173 // Script and scope have different hosts 174 SendRegister(kProviderId, 175 GURL("https://foo.example.com/"), 176 GURL("https://foo.example.com/bar")); 177 EXPECT_EQ(5, dispatcher_host_->bad_messages_received_count_); 178 179 // Script and scope URLs are invalid 180 SendRegister(kProviderId, 181 GURL(), 182 GURL("h@ttps://@")); 183 EXPECT_EQ(6, dispatcher_host_->bad_messages_received_count_); 184} 185 186TEST_F(ServiceWorkerDispatcherHostTest, Unregister_SameOrigin) { 187 const int64 kProviderId = 99; // Dummy value 188 scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost( 189 kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL)); 190 host->SetDocumentUrl(GURL("http://www.example.com/foo")); 191 base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr(); 192 context()->AddProviderHost(host.Pass()); 193 194 Unregister(kProviderId, 195 GURL("http://www.example.com/"), 196 ServiceWorkerMsg_ServiceWorkerUnregistered::ID); 197} 198 199TEST_F(ServiceWorkerDispatcherHostTest, Unregister_CrossOrigin) { 200 const int64 kProviderId = 99; // Dummy value 201 scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost( 202 kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL)); 203 host->SetDocumentUrl(GURL("http://www.example.com/foo")); 204 base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr(); 205 context()->AddProviderHost(host.Pass()); 206 207 SendUnregister(kProviderId, GURL("http://foo.example.com/")); 208 EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_); 209} 210 211TEST_F(ServiceWorkerDispatcherHostTest, EarlyContextDeletion) { 212 helper_->ShutdownContext(); 213 214 // Let the shutdown reach the simulated IO thread. 215 base::RunLoop().RunUntilIdle(); 216 217 Register(-1, 218 GURL(), 219 GURL(), 220 ServiceWorkerMsg_ServiceWorkerRegistrationError::ID); 221} 222 223TEST_F(ServiceWorkerDispatcherHostTest, ProviderCreatedAndDestroyed) { 224 const int kProviderId = 1001; // Test with a value != kRenderProcessId. 225 226 dispatcher_host_->OnMessageReceived( 227 ServiceWorkerHostMsg_ProviderCreated(kProviderId)); 228 EXPECT_TRUE(context()->GetProviderHost(kRenderProcessId, kProviderId)); 229 230 // Two with the same ID should be seen as a bad message. 231 dispatcher_host_->OnMessageReceived( 232 ServiceWorkerHostMsg_ProviderCreated(kProviderId)); 233 EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_); 234 235 dispatcher_host_->OnMessageReceived( 236 ServiceWorkerHostMsg_ProviderDestroyed(kProviderId)); 237 EXPECT_FALSE(context()->GetProviderHost(kRenderProcessId, kProviderId)); 238 239 // Destroying an ID that does not exist warrants a bad message. 240 dispatcher_host_->OnMessageReceived( 241 ServiceWorkerHostMsg_ProviderDestroyed(kProviderId)); 242 EXPECT_EQ(2, dispatcher_host_->bad_messages_received_count_); 243 244 // Deletion of the dispatcher_host should cause providers for that 245 // process to get deleted as well. 246 dispatcher_host_->OnMessageReceived( 247 ServiceWorkerHostMsg_ProviderCreated(kProviderId)); 248 EXPECT_TRUE(context()->GetProviderHost(kRenderProcessId, kProviderId)); 249 EXPECT_TRUE(dispatcher_host_->HasOneRef()); 250 dispatcher_host_ = NULL; 251 EXPECT_FALSE(context()->GetProviderHost(kRenderProcessId, kProviderId)); 252} 253 254TEST_F(ServiceWorkerDispatcherHostTest, GetRegistration_SameOrigin) { 255 const int64 kProviderId = 99; // Dummy value 256 scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost( 257 kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL)); 258 host->SetDocumentUrl(GURL("https://www.example.com/foo")); 259 base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr(); 260 context()->AddProviderHost(host.Pass()); 261 262 GetRegistration(kProviderId, 263 GURL("https://www.example.com/"), 264 ServiceWorkerMsg_DidGetRegistration::ID); 265} 266 267TEST_F(ServiceWorkerDispatcherHostTest, GetRegistration_CrossOrigin) { 268 const int64 kProviderId = 99; // Dummy value 269 scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost( 270 kRenderProcessId, kProviderId, context()->AsWeakPtr(), NULL)); 271 host->SetDocumentUrl(GURL("https://www.example.com/foo")); 272 base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr(); 273 context()->AddProviderHost(host.Pass()); 274 275 SendGetRegistration(kProviderId, GURL("https://foo.example.com/")); 276 EXPECT_EQ(1, dispatcher_host_->bad_messages_received_count_); 277} 278 279TEST_F(ServiceWorkerDispatcherHostTest, GetRegistration_EarlyContextDeletion) { 280 helper_->ShutdownContext(); 281 282 // Let the shutdown reach the simulated IO thread. 283 base::RunLoop().RunUntilIdle(); 284 285 GetRegistration(-1, 286 GURL(), 287 ServiceWorkerMsg_ServiceWorkerGetRegistrationError::ID); 288} 289 290} // namespace content 291