diff options
author | nhiroki <nhiroki@chromium.org> | 2016-03-21 17:26:26 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-22 00:28:41 +0000 |
commit | f6da9a0a7eb3a919aa29749017321c9bae8bfa8b (patch) | |
tree | 5c1e9287a275439f4671cd90c0547318b859f2f4 | |
parent | 679e44bbdc57ae16cc8a1f90e2a338b84e8ad5de (diff) | |
download | chromium_src-f6da9a0a7eb3a919aa29749017321c9bae8bfa8b.zip chromium_src-f6da9a0a7eb3a919aa29749017321c9bae8bfa8b.tar.gz chromium_src-f6da9a0a7eb3a919aa29749017321c9bae8bfa8b.tar.bz2 |
ServiceWorker: Release a reference when it fails to dispatch ExtendableMessageEvent
This CL makes sure to release a reference to ServiceWorkerHandle that was
supposed to be sent to the destination.
Note: ExtendableMessageEvent is still behind a flag and resource leaks due to
this have not happened in release builds.
BUG=543198
Review URL: https://codereview.chromium.org/1799413002
Cr-Commit-Position: refs/heads/master@{#382455}
10 files changed, 298 insertions, 77 deletions
diff --git a/content/browser/message_port_service.cc b/content/browser/message_port_service.cc index 21fc76d..789e2aa 100644 --- a/content/browser/message_port_service.cc +++ b/content/browser/message_port_service.cc @@ -295,6 +295,13 @@ void MessagePortService::HoldMessages(int message_port_id) { message_ports_[message_port_id].hold_messages_for_destination = true; } +bool MessagePortService::AreMessagesHeld(int message_port_id) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (!message_ports_.count(message_port_id)) + return false; + return message_ports_[message_port_id].hold_messages_for_destination; +} + void MessagePortService::ClosePort(int message_port_id) { DCHECK_CURRENTLY_ON(BrowserThread::IO); if (!message_ports_.count(message_port_id)) { diff --git a/content/browser/message_port_service.h b/content/browser/message_port_service.h index c3aeadb..b46a7fa3 100644 --- a/content/browser/message_port_service.h +++ b/content/browser/message_port_service.h @@ -67,6 +67,9 @@ class CONTENT_EXPORT MessagePortService { // clean up the port. void HoldMessages(int message_port_id); + // Returns true if messages for a message port are on hold. + bool AreMessagesHeld(int message_port_id); + // Closes and cleans up the message port. void ClosePort(int message_port_id); diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc index 21b99de..ff3d6ec 100644 --- a/content/browser/service_worker/embedded_worker_test_helper.cc +++ b/content/browser/service_worker/embedded_worker_test_helper.cc @@ -187,6 +187,8 @@ bool EmbeddedWorkerTestHelper::OnMessageToWorker( current_embedded_worker_id_ = embedded_worker_id; IPC_BEGIN_MESSAGE_MAP(EmbeddedWorkerTestHelper, message) IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ActivateEvent, OnActivateEventStub) + IPC_MESSAGE_HANDLER(ServiceWorkerMsg_ExtendableMessageEvent, + OnExtendableMessageEventStub) IPC_MESSAGE_HANDLER(ServiceWorkerMsg_InstallEvent, OnInstallEventStub) IPC_MESSAGE_HANDLER(ServiceWorkerMsg_FetchEvent, OnFetchEventStub) IPC_MESSAGE_HANDLER(ServiceWorkerMsg_PushEvent, OnPushEventStub) @@ -207,6 +209,13 @@ void EmbeddedWorkerTestHelper::OnActivateEvent(int embedded_worker_id, blink::WebServiceWorkerEventResultCompleted)); } +void EmbeddedWorkerTestHelper::OnExtendableMessageEvent(int embedded_worker_id, + int request_id) { + SimulateSend(new ServiceWorkerHostMsg_ExtendableMessageEventFinished( + embedded_worker_id, request_id, + blink::WebServiceWorkerEventResultCompleted)); +} + void EmbeddedWorkerTestHelper::OnInstallEvent(int embedded_worker_id, int request_id) { // The installing worker may have been doomed and terminated. @@ -362,11 +371,18 @@ void EmbeddedWorkerTestHelper::OnMessageToWorkerStub( void EmbeddedWorkerTestHelper::OnActivateEventStub(int request_id) { base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&EmbeddedWorkerTestHelper::OnActivateEvent, - weak_factory_.GetWeakPtr(), - current_embedded_worker_id_, - request_id)); + FROM_HERE, base::Bind(&EmbeddedWorkerTestHelper::OnActivateEvent, + weak_factory_.GetWeakPtr(), + current_embedded_worker_id_, request_id)); +} + +void EmbeddedWorkerTestHelper::OnExtendableMessageEventStub( + int request_id, + const ServiceWorkerMsg_ExtendableMessageEvent_Params& params) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&EmbeddedWorkerTestHelper::OnExtendableMessageEvent, + weak_factory_.GetWeakPtr(), + current_embedded_worker_id_, request_id)); } void EmbeddedWorkerTestHelper::OnInstallEventStub(int request_id) { diff --git a/content/browser/service_worker/embedded_worker_test_helper.h b/content/browser/service_worker/embedded_worker_test_helper.h index 40de8b3..a9d34b5 100644 --- a/content/browser/service_worker/embedded_worker_test_helper.h +++ b/content/browser/service_worker/embedded_worker_test_helper.h @@ -21,8 +21,9 @@ #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" -struct EmbeddedWorkerMsg_StartWorker_Params; class GURL; +struct EmbeddedWorkerMsg_StartWorker_Params; +struct ServiceWorkerMsg_ExtendableMessageEvent_Params; namespace content { @@ -30,11 +31,11 @@ class EmbeddedWorkerRegistry; class EmbeddedWorkerTestHelper; class MessagePortMessageFilter; class MockRenderProcessHost; -struct PushEventPayload; class ServiceWorkerContextCore; class ServiceWorkerContextWrapper; -struct ServiceWorkerFetchRequest; class TestBrowserContext; +struct PushEventPayload; +struct ServiceWorkerFetchRequest; // In-Process EmbeddedWorker test helper. // @@ -80,7 +81,7 @@ class EmbeddedWorkerTestHelper : public IPC::Sender, int GetNextThreadId() { return next_thread_id_++; } - int mock_render_process_id() const { return mock_render_process_id_;} + int mock_render_process_id() const { return mock_render_process_id_; } MockRenderProcessHost* mock_render_process_host() { return render_process_host_.get(); } @@ -122,6 +123,7 @@ class EmbeddedWorkerTestHelper : public IPC::Sender, // worker. By default they just return success via // SimulateSendReplyToBrowser. virtual void OnActivateEvent(int embedded_worker_id, int request_id); + virtual void OnExtendableMessageEvent(int embedded_worker_id, int request_id); virtual void OnInstallEvent(int embedded_worker_id, int request_id); virtual void OnFetchEvent(int embedded_worker_id, int request_id, @@ -153,6 +155,9 @@ class EmbeddedWorkerTestHelper : public IPC::Sender, int embedded_worker_id, const IPC::Message& message); void OnActivateEventStub(int request_id); + void OnExtendableMessageEventStub( + int request_id, + const ServiceWorkerMsg_ExtendableMessageEvent_Params& params); void OnInstallEventStub(int request_id); void OnFetchEventStub(int request_id, const ServiceWorkerFetchRequest& request); diff --git a/content/browser/service_worker/service_worker_dispatcher_host.cc b/content/browser/service_worker/service_worker_dispatcher_host.cc index f6b90cd..4c9d6e1 100644 --- a/content/browser/service_worker/service_worker_dispatcher_host.cc +++ b/content/browser/service_worker/service_worker_dispatcher_host.cc @@ -700,6 +700,19 @@ void ServiceWorkerDispatcherHost::OnPostMessageToWorker( return; } + DispatchExtendableMessageEvent( + make_scoped_refptr(handle->version()), message, source_origin, + sent_message_ports, sender_provider_host, + base::Bind(&ServiceWorkerUtils::NoOpStatusCallback)); +} + +void ServiceWorkerDispatcherHost::DispatchExtendableMessageEvent( + scoped_refptr<ServiceWorkerVersion> worker, + const base::string16& message, + const url::Origin& source_origin, + const std::vector<TransferredMessagePort>& sent_message_ports, + ServiceWorkerProviderHost* sender_provider_host, + const StatusCallback& callback) { for (const TransferredMessagePort& port : sent_message_ports) MessagePortService::GetInstance()->HoldMessages(port.id); @@ -709,20 +722,17 @@ void ServiceWorkerDispatcherHost::OnPostMessageToWorker( case SERVICE_WORKER_PROVIDER_FOR_SHARED_WORKER: service_worker_client_utils::GetClient( sender_provider_host, - base::Bind( - &ServiceWorkerDispatcherHost::DispatchExtendableMessageEvent< - ServiceWorkerClientInfo>, - this, make_scoped_refptr(handle->version()), message, - source_origin, sent_message_ports)); + base::Bind(&ServiceWorkerDispatcherHost:: + DispatchExtendableMessageEventInternal< + ServiceWorkerClientInfo>, + this, worker, message, source_origin, sent_message_ports, + callback)); break; case SERVICE_WORKER_PROVIDER_FOR_CONTROLLER: - // TODO(nhiroki): Decrement a reference to ServiceWorkerHandle if starting - // worker fails (http://crbug.com/543198). RunSoon(base::Bind( - &ServiceWorkerDispatcherHost::DispatchExtendableMessageEvent< + &ServiceWorkerDispatcherHost::DispatchExtendableMessageEventInternal< ServiceWorkerObjectInfo>, - this, make_scoped_refptr(handle->version()), message, source_origin, - sent_message_ports, + this, worker, message, source_origin, sent_message_ports, callback, sender_provider_host->GetOrCreateServiceWorkerHandle( sender_provider_host->running_hosted_version()))); break; @@ -865,15 +875,16 @@ void ServiceWorkerDispatcherHost::OnSetHostedVersionId(int provider_id, } template <typename SourceInfo> -void ServiceWorkerDispatcherHost::DispatchExtendableMessageEvent( +void ServiceWorkerDispatcherHost::DispatchExtendableMessageEventInternal( scoped_refptr<ServiceWorkerVersion> worker, const base::string16& message, const url::Origin& source_origin, const std::vector<TransferredMessagePort>& sent_message_ports, + const StatusCallback& callback, const SourceInfo& source_info) { if (!source_info.IsValid()) { - DidFailToDispatchExtendableMessageEvent(sent_message_ports, - SERVICE_WORKER_ERROR_FAILED); + DidFailToDispatchExtendableMessageEvent<SourceInfo>( + sent_message_ports, source_info, callback, SERVICE_WORKER_ERROR_FAILED); return; } worker->RunAfterStartWorker( @@ -881,10 +892,11 @@ void ServiceWorkerDispatcherHost::DispatchExtendableMessageEvent( base::Bind(&ServiceWorkerDispatcherHost:: DispatchExtendableMessageEventAfterStartWorker, this, worker, message, source_origin, sent_message_ports, - ExtendableMessageEventSource(source_info)), + ExtendableMessageEventSource(source_info), callback), base::Bind( - &ServiceWorkerDispatcherHost::DidFailToDispatchExtendableMessageEvent, - this, sent_message_ports)); + &ServiceWorkerDispatcherHost::DidFailToDispatchExtendableMessageEvent< + SourceInfo>, + this, sent_message_ports, source_info, callback)); } void ServiceWorkerDispatcherHost:: @@ -893,10 +905,10 @@ void ServiceWorkerDispatcherHost:: const base::string16& message, const url::Origin& source_origin, const std::vector<TransferredMessagePort>& sent_message_ports, - const ExtendableMessageEventSource& source) { + const ExtendableMessageEventSource& source, + const StatusCallback& callback) { int request_id = - worker->StartRequest(ServiceWorkerMetrics::EventType::MESSAGE, - base::Bind(&ServiceWorkerUtils::NoOpStatusCallback)); + worker->StartRequest(ServiceWorkerMetrics::EventType::MESSAGE, callback); MessagePortMessageFilter* filter = worker->embedded_worker()->message_port_message_filter(); @@ -923,12 +935,33 @@ void ServiceWorkerDispatcherHost:: request_id, ServiceWorkerMsg_ExtendableMessageEvent(request_id, params)); } +template <typename SourceInfo> void ServiceWorkerDispatcherHost::DidFailToDispatchExtendableMessageEvent( const std::vector<TransferredMessagePort>& sent_message_ports, + const SourceInfo& source_info, + const StatusCallback& callback, ServiceWorkerStatusCode status) { // Transfering the message ports failed, so destroy the ports. for (const TransferredMessagePort& port : sent_message_ports) MessagePortService::GetInstance()->ClosePort(port.id); + if (source_info.IsValid()) + ReleaseSourceInfo(source_info); + callback.Run(status); +} + +void ServiceWorkerDispatcherHost::ReleaseSourceInfo( + const ServiceWorkerClientInfo& source_info) { + // ServiceWorkerClientInfo is just a snapshot of the client. There is no need + // to do anything for it. +} + +void ServiceWorkerDispatcherHost::ReleaseSourceInfo( + const ServiceWorkerObjectInfo& source_info) { + ServiceWorkerHandle* handle = handles_.Lookup(source_info.handle_id); + DCHECK(handle); + handle->DecrementRefCount(); + if (handle->HasNoRefCount()) + handles_.Remove(source_info.handle_id); } ServiceWorkerRegistrationHandle* diff --git a/content/browser/service_worker/service_worker_dispatcher_host.h b/content/browser/service_worker/service_worker_dispatcher_host.h index e1f57d0..b0287ffba 100644 --- a/content/browser/service_worker/service_worker_dispatcher_host.h +++ b/content/browser/service_worker/service_worker_dispatcher_host.h @@ -88,8 +88,11 @@ class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter { private: friend class BrowserThread; friend class base::DeleteHelper<ServiceWorkerDispatcherHost>; + friend class ServiceWorkerDispatcherHostTest; friend class TestingServiceWorkerDispatcherHost; + using StatusCallback = base::Callback<void(ServiceWorkerStatusCode status)>; + // IPC Message handlers void OnRegisterServiceWorker(int thread_id, int request_id, @@ -154,22 +157,36 @@ class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter { void OnTerminateWorker(int handle_id); - template <typename SourceInfo> void DispatchExtendableMessageEvent( scoped_refptr<ServiceWorkerVersion> worker, const base::string16& message, const url::Origin& source_origin, const std::vector<TransferredMessagePort>& sent_message_ports, + ServiceWorkerProviderHost* sender_provider_host, + const StatusCallback& callback); + template <typename SourceInfo> + void DispatchExtendableMessageEventInternal( + scoped_refptr<ServiceWorkerVersion> worker, + const base::string16& message, + const url::Origin& source_origin, + const std::vector<TransferredMessagePort>& sent_message_ports, + const StatusCallback& callback, const SourceInfo& source_info); void DispatchExtendableMessageEventAfterStartWorker( scoped_refptr<ServiceWorkerVersion> worker, const base::string16& message, const url::Origin& source_origin, const std::vector<TransferredMessagePort>& sent_message_ports, - const ExtendableMessageEventSource& source); + const ExtendableMessageEventSource& source, + const StatusCallback& callback); + template <typename SourceInfo> void DidFailToDispatchExtendableMessageEvent( const std::vector<TransferredMessagePort>& sent_message_ports, + const SourceInfo& source_info, + const StatusCallback& callback, ServiceWorkerStatusCode status); + void ReleaseSourceInfo(const ServiceWorkerClientInfo& source_info); + void ReleaseSourceInfo(const ServiceWorkerObjectInfo& source_info); ServiceWorkerRegistrationHandle* FindRegistrationHandle( int provider_id, diff --git a/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc b/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc index 9bce9ae..d8a370a 100644 --- a/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc +++ b/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc @@ -11,11 +11,13 @@ #include "base/files/file_path.h" #include "base/run_loop.h" #include "content/browser/browser_thread_impl.h" +#include "content/browser/message_port_service.h" #include "content/browser/service_worker/embedded_worker_instance.h" #include "content/browser/service_worker/embedded_worker_registry.h" #include "content/browser/service_worker/embedded_worker_test_helper.h" #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" +#include "content/browser/service_worker/service_worker_handle.h" #include "content/common/service_worker/embedded_worker_messages.h" #include "content/common/service_worker/service_worker_messages.h" #include "content/public/common/content_switches.h" @@ -35,8 +37,17 @@ static void SaveStatusCallback(bool* called, *out = status; } +void SetUpDummyMessagePort(std::vector<TransferredMessagePort>* ports) { + int port_id = -1; + MessagePortService::GetInstance()->Create(MSG_ROUTING_NONE, nullptr, + &port_id); + TransferredMessagePort dummy_port; + dummy_port.id = port_id; + ports->push_back(dummy_port); } +} // namespace + static const int kRenderFrameId = 1; class TestingServiceWorkerDispatcherHost : public ServiceWorkerDispatcherHost { @@ -65,25 +76,81 @@ class TestingServiceWorkerDispatcherHost : public ServiceWorkerDispatcherHost { ~TestingServiceWorkerDispatcherHost() override {} }; +class FailToStartWorkerTestHelper : public EmbeddedWorkerTestHelper { + public: + FailToStartWorkerTestHelper() : EmbeddedWorkerTestHelper(base::FilePath()) {} + + void OnStartWorker(int embedded_worker_id, + int64_t service_worker_version_id, + const GURL& scope, + const GURL& script_url, + bool pause_after_download) override { + EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id); + registry()->OnWorkerStopped(worker->process_id(), embedded_worker_id); + } +}; + class ServiceWorkerDispatcherHostTest : public testing::Test { protected: ServiceWorkerDispatcherHostTest() : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {} void SetUp() override { - helper_.reset(new EmbeddedWorkerTestHelper(base::FilePath())); - dispatcher_host_ = new TestingServiceWorkerDispatcherHost( - helper_->mock_render_process_id(), context_wrapper(), - &resource_context_, helper_.get()); + Initialize(make_scoped_ptr(new EmbeddedWorkerTestHelper(base::FilePath()))); } - void TearDown() override { helper_.reset(); } + void TearDown() override { + version_ = nullptr; + registration_ = nullptr; + helper_.reset(); + } ServiceWorkerContextCore* context() { return helper_->context(); } ServiceWorkerContextWrapper* context_wrapper() { return helper_->context_wrapper(); } + void Initialize(scoped_ptr<EmbeddedWorkerTestHelper> helper) { + helper_.reset(helper.release()); + dispatcher_host_ = new TestingServiceWorkerDispatcherHost( + helper_->mock_render_process_id(), context_wrapper(), + &resource_context_, helper_.get()); + } + + void SetUpRegistration(const GURL& scope, const GURL& script_url) { + registration_ = new ServiceWorkerRegistration( + scope, 1L, helper_->context()->AsWeakPtr()); + version_ = new ServiceWorkerVersion(registration_.get(), script_url, 1L, + helper_->context()->AsWeakPtr()); + std::vector<ServiceWorkerDatabase::ResourceRecord> records; + records.push_back( + ServiceWorkerDatabase::ResourceRecord(10, version_->script_url(), 100)); + version_->script_cache_map()->SetResources(records); + + // Make the registration findable via storage functions. + helper_->context()->storage()->LazyInitialize(base::Bind(&base::DoNothing)); + base::RunLoop().RunUntilIdle(); + bool called = false; + ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE; + helper_->context()->storage()->StoreRegistration( + registration_.get(), version_.get(), + base::Bind(&SaveStatusCallback, &called, &status)); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(called); + EXPECT_EQ(SERVICE_WORKER_OK, status); + } + + void SendProviderCreated(ServiceWorkerProviderType type, + const GURL& pattern) { + const int64_t kProviderId = 99; + dispatcher_host_->OnMessageReceived(ServiceWorkerHostMsg_ProviderCreated( + kProviderId, MSG_ROUTING_NONE, type)); + helper_->SimulateAddProcessToPattern(pattern, + helper_->mock_render_process_id()); + provider_host_ = context()->GetProviderHost( + helper_->mock_render_process_id(), kProviderId); + } + void SendRegister(int64_t provider_id, GURL pattern, GURL worker_url) { dispatcher_host_->OnMessageReceived( ServiceWorkerHostMsg_RegisterServiceWorker( @@ -146,6 +213,18 @@ class ServiceWorkerDispatcherHostTest : public testing::Test { dispatcher_host_->ipc_sink()->ClearMessages(); } + void DispatchExtendableMessageEvent( + scoped_refptr<ServiceWorkerVersion> worker, + const base::string16& message, + const url::Origin& source_origin, + const std::vector<TransferredMessagePort>& sent_message_ports, + ServiceWorkerProviderHost* sender_provider_host, + const ServiceWorkerDispatcherHost::StatusCallback& callback) { + dispatcher_host_->DispatchExtendableMessageEvent( + std::move(worker), message, source_origin, sent_message_ports, + sender_provider_host, callback); + } + ServiceWorkerProviderHost* CreateServiceWorkerProviderHost(int provider_id) { return new ServiceWorkerProviderHost( helper_->mock_render_process_id(), kRenderFrameId, provider_id, @@ -153,11 +232,13 @@ class ServiceWorkerDispatcherHostTest : public testing::Test { dispatcher_host_.get()); } - TestBrowserThreadBundle browser_thread_bundle_; content::MockResourceContext resource_context_; scoped_ptr<EmbeddedWorkerTestHelper> helper_; scoped_refptr<TestingServiceWorkerDispatcherHost> dispatcher_host_; + scoped_refptr<ServiceWorkerRegistration> registration_; + scoped_refptr<ServiceWorkerVersion> version_; + ServiceWorkerProviderHost* provider_host_; }; class ServiceWorkerTestContentBrowserClient : public TestContentBrowserClient { @@ -526,61 +607,33 @@ TEST_F(ServiceWorkerDispatcherHostTest, GetRegistrations_EarlyContextDeletion) { } TEST_F(ServiceWorkerDispatcherHostTest, CleanupOnRendererCrash) { + GURL pattern = GURL("http://www.example.com/"); + GURL script_url = GURL("http://www.example.com/service_worker.js"); int process_id = helper_->mock_render_process_id(); - // Add a provider and worker. - const int64_t kProviderId = 99; // Dummy value - dispatcher_host_->OnMessageReceived(ServiceWorkerHostMsg_ProviderCreated( - kProviderId, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_WINDOW)); + SendProviderCreated(SERVICE_WORKER_PROVIDER_FOR_WINDOW, pattern); + SetUpRegistration(pattern, script_url); + int64_t provider_id = provider_host_->provider_id(); - GURL pattern = GURL("http://www.example.com/"); - scoped_refptr<ServiceWorkerRegistration> registration( - new ServiceWorkerRegistration(pattern, - 1L, - helper_->context()->AsWeakPtr())); - scoped_refptr<ServiceWorkerVersion> version( - new ServiceWorkerVersion(registration.get(), - GURL("http://www.example.com/service_worker.js"), - 1L, - helper_->context()->AsWeakPtr())); - std::vector<ServiceWorkerDatabase::ResourceRecord> records; - records.push_back( - ServiceWorkerDatabase::ResourceRecord(10, version->script_url(), 100)); - version->script_cache_map()->SetResources(records); - - // Make the registration findable via storage functions. - helper_->context()->storage()->LazyInitialize(base::Bind(&base::DoNothing)); - base::RunLoop().RunUntilIdle(); + // Start up the worker. bool called = false; ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_ABORT; - helper_->context()->storage()->StoreRegistration( - registration.get(), - version.get(), - base::Bind(&SaveStatusCallback, &called, &status)); - base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(called); - ASSERT_EQ(SERVICE_WORKER_OK, status); - - helper_->SimulateAddProcessToPattern(pattern, process_id); - - // Start up the worker. - status = SERVICE_WORKER_ERROR_ABORT; - version->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN, - base::Bind(&SaveStatusCallback, &called, &status)); + version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN, + base::Bind(&SaveStatusCallback, &called, &status)); base::RunLoop().RunUntilIdle(); EXPECT_TRUE(called); EXPECT_EQ(SERVICE_WORKER_OK, status); - EXPECT_TRUE(context()->GetProviderHost(process_id, kProviderId)); - EXPECT_EQ(ServiceWorkerVersion::RUNNING, version->running_status()); + EXPECT_TRUE(context()->GetProviderHost(process_id, provider_id)); + EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status()); // Simulate the render process crashing. dispatcher_host_->OnFilterRemoved(); // The dispatcher host should clean up the state from the process. - EXPECT_FALSE(context()->GetProviderHost(process_id, kProviderId)); - EXPECT_EQ(ServiceWorkerVersion::STOPPED, version->running_status()); + EXPECT_FALSE(context()->GetProviderHost(process_id, provider_id)); + EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status()); // We should be able to hook up a new dispatcher host although the old object // is not yet destroyed. This is what the browser does when reusing a crashed @@ -593,8 +646,89 @@ TEST_F(ServiceWorkerDispatcherHostTest, CleanupOnRendererCrash) { // the old dispatcher cleaned up the old provider host, the new one won't // complain. new_dispatcher_host->OnMessageReceived(ServiceWorkerHostMsg_ProviderCreated( - kProviderId, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_WINDOW)); + provider_id, MSG_ROUTING_NONE, SERVICE_WORKER_PROVIDER_FOR_WINDOW)); EXPECT_EQ(0, new_dispatcher_host->bad_messages_received_count_); } +TEST_F(ServiceWorkerDispatcherHostTest, DispatchExtendableMessageEvent) { + GURL pattern = GURL("http://www.example.com/"); + GURL script_url = GURL("http://www.example.com/service_worker.js"); + + SendProviderCreated(SERVICE_WORKER_PROVIDER_FOR_CONTROLLER, pattern); + SetUpRegistration(pattern, script_url); + + // Set the running hosted version so that we can retrieve a valid service + // worker object information for the source attribute of the message event. + provider_host_->running_hosted_version_ = version_; + + // Set aside the initial refcount of the worker handle. + provider_host_->GetOrCreateServiceWorkerHandle(version_.get()); + ServiceWorkerHandle* sender_worker_handle = + dispatcher_host_->FindServiceWorkerHandle(provider_host_->provider_id(), + version_->version_id()); + const int ref_count = sender_worker_handle->ref_count(); + + // Dispatch ExtendableMessageEvent. + std::vector<TransferredMessagePort> ports; + SetUpDummyMessagePort(&ports); + bool called = false; + ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE; + DispatchExtendableMessageEvent( + version_, base::string16(), url::Origin(version_->scope().GetOrigin()), + ports, provider_host_, base::Bind(&SaveStatusCallback, &called, &status)); + for (TransferredMessagePort port : ports) + EXPECT_TRUE(MessagePortService::GetInstance()->AreMessagesHeld(port.id)); + EXPECT_EQ(ref_count + 1, sender_worker_handle->ref_count()); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(called); + EXPECT_EQ(SERVICE_WORKER_OK, status); + + // Messages should be held until ports are created at the destination. + for (TransferredMessagePort port : ports) + EXPECT_TRUE(MessagePortService::GetInstance()->AreMessagesHeld(port.id)); + + EXPECT_EQ(ref_count + 1, sender_worker_handle->ref_count()); +} + +TEST_F(ServiceWorkerDispatcherHostTest, DispatchExtendableMessageEvent_Fail) { + GURL pattern = GURL("http://www.example.com/"); + GURL script_url = GURL("http://www.example.com/service_worker.js"); + + Initialize(make_scoped_ptr(new FailToStartWorkerTestHelper)); + SendProviderCreated(SERVICE_WORKER_PROVIDER_FOR_CONTROLLER, pattern); + SetUpRegistration(pattern, script_url); + + // Set the running hosted version so that we can retrieve a valid service + // worker object information for the source attribute of the message event. + provider_host_->running_hosted_version_ = version_; + + // Set aside the initial refcount of the worker handle. + provider_host_->GetOrCreateServiceWorkerHandle(version_.get()); + ServiceWorkerHandle* sender_worker_handle = + dispatcher_host_->FindServiceWorkerHandle(provider_host_->provider_id(), + version_->version_id()); + const int ref_count = sender_worker_handle->ref_count(); + + // Try to dispatch ExtendableMessageEvent. This should fail to start the + // worker and to dispatch the event. + std::vector<TransferredMessagePort> ports; + SetUpDummyMessagePort(&ports); + bool called = false; + ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE; + DispatchExtendableMessageEvent( + version_, base::string16(), url::Origin(version_->scope().GetOrigin()), + ports, provider_host_, base::Bind(&SaveStatusCallback, &called, &status)); + for (TransferredMessagePort port : ports) + EXPECT_TRUE(MessagePortService::GetInstance()->AreMessagesHeld(port.id)); + EXPECT_EQ(ref_count + 1, sender_worker_handle->ref_count()); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(called); + EXPECT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, status); + + // The error callback should clean up the ports and handle. + for (TransferredMessagePort port : ports) + EXPECT_FALSE(MessagePortService::GetInstance()->AreMessagesHeld(port.id)); + EXPECT_EQ(ref_count, sender_worker_handle->ref_count()); +} + } // namespace content diff --git a/content/browser/service_worker/service_worker_handle.h b/content/browser/service_worker/service_worker_handle.h index a9c0e44..4d8651a 100644 --- a/content/browser/service_worker/service_worker_handle.h +++ b/content/browser/service_worker/service_worker_handle.h @@ -54,6 +54,7 @@ class CONTENT_EXPORT ServiceWorkerHandle int handle_id() const { return handle_id_; } ServiceWorkerVersion* version() { return version_.get(); } + int ref_count() const { return ref_count_; } bool HasNoRefCount() const { return ref_count_ <= 0; } void IncrementRefCount(); void DecrementRefCount(); diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h index 8bb8d92..0434522 100644 --- a/content/browser/service_worker/service_worker_provider_host.h +++ b/content/browser/service_worker/service_worker_provider_host.h @@ -248,6 +248,10 @@ class CONTENT_EXPORT ServiceWorkerProviderHost Update_ElongatedScript); FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWriteToCacheJobTest, Update_EmptyScript); + FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDispatcherHostTest, + DispatchExtendableMessageEvent); + FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDispatcherHostTest, + DispatchExtendableMessageEvent_Fail); FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest, UpdateBefore24Hours); FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest, diff --git a/content/browser/service_worker/service_worker_storage.h b/content/browser/service_worker/service_worker_storage.h index 55b2b21..c4dbe08 100644 --- a/content/browser/service_worker/service_worker_storage.h +++ b/content/browser/service_worker/service_worker_storage.h @@ -224,6 +224,7 @@ class CONTENT_EXPORT ServiceWorkerStorage void PurgeResources(const ResourceList& resources); private: + friend class ServiceWorkerDispatcherHostTest; friend class ServiceWorkerHandleTest; friend class ServiceWorkerStorageTest; friend class ServiceWorkerResourceStorageTest; |