summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornhiroki <nhiroki@chromium.org>2016-03-21 17:26:26 -0700
committerCommit bot <commit-bot@chromium.org>2016-03-22 00:28:41 +0000
commitf6da9a0a7eb3a919aa29749017321c9bae8bfa8b (patch)
tree5c1e9287a275439f4671cd90c0547318b859f2f4
parent679e44bbdc57ae16cc8a1f90e2a338b84e8ad5de (diff)
downloadchromium_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}
-rw-r--r--content/browser/message_port_service.cc7
-rw-r--r--content/browser/message_port_service.h3
-rw-r--r--content/browser/service_worker/embedded_worker_test_helper.cc26
-rw-r--r--content/browser/service_worker/embedded_worker_test_helper.h13
-rw-r--r--content/browser/service_worker/service_worker_dispatcher_host.cc71
-rw-r--r--content/browser/service_worker/service_worker_dispatcher_host.h21
-rw-r--r--content/browser/service_worker/service_worker_dispatcher_host_unittest.cc228
-rw-r--r--content/browser/service_worker/service_worker_handle.h1
-rw-r--r--content/browser/service_worker/service_worker_provider_host.h4
-rw-r--r--content/browser/service_worker/service_worker_storage.h1
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;