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.
5 #include "content/browser/service_worker/service_worker_provider_host.h"
7 #include "base/stl_util.h"
8 #include "content/browser/message_port_message_filter.h"
9 #include "content/browser/service_worker/service_worker_context_core.h"
10 #include "content/browser/service_worker/service_worker_context_request_handler.h"
11 #include "content/browser/service_worker/service_worker_controllee_request_handler.h"
12 #include "content/browser/service_worker/service_worker_dispatcher_host.h"
13 #include "content/browser/service_worker/service_worker_handle.h"
14 #include "content/browser/service_worker/service_worker_registration_handle.h"
15 #include "content/browser/service_worker/service_worker_utils.h"
16 #include "content/browser/service_worker/service_worker_version.h"
17 #include "content/common/service_worker/service_worker_messages.h"
21 static const int kDocumentMainThreadId = 0;
23 ServiceWorkerProviderHost::ServiceWorkerProviderHost(
24 int process_id, int provider_id,
25 base::WeakPtr<ServiceWorkerContextCore> context,
26 ServiceWorkerDispatcherHost* dispatcher_host)
27 : process_id_(process_id),
28 provider_id_(provider_id),
30 dispatcher_host_(dispatcher_host) {
33 ServiceWorkerProviderHost::~ServiceWorkerProviderHost() {
34 // Clear docurl so the deferred activation of a waiting worker
35 // won't associate the new version with a provider being destroyed.
36 document_url_ = GURL();
37 if (controlling_version_)
38 controlling_version_->RemoveControllee(this);
40 active_version_->RemovePotentialControllee(this);
42 waiting_version_->RemovePotentialControllee(this);
43 if (installing_version_)
44 installing_version_->RemovePotentialControllee(this);
45 if (associated_registration_)
46 associated_registration_->RemoveListener(this);
49 void ServiceWorkerProviderHost::OnVersionAttributesChanged(
50 ServiceWorkerRegistration* registration,
51 ChangedVersionAttributesMask changed_mask,
52 const ServiceWorkerRegistrationInfo& info) {
53 DCHECK_EQ(associated_registration_, registration);
54 SetVersionAttributes(registration->installing_version(),
55 registration->waiting_version(),
56 registration->active_version());
59 void ServiceWorkerProviderHost::OnRegistrationFailed(
60 ServiceWorkerRegistration* registration) {
61 DCHECK_EQ(associated_registration_, registration);
62 UnassociateRegistration();
65 void ServiceWorkerProviderHost::SetDocumentUrl(const GURL& url) {
66 DCHECK(!url.has_ref());
70 void ServiceWorkerProviderHost::SetVersionAttributes(
71 ServiceWorkerVersion* installing_version,
72 ServiceWorkerVersion* waiting_version,
73 ServiceWorkerVersion* active_version) {
74 ChangedVersionAttributesMask mask;
76 if (installing_version != installing_version_) {
77 SetVersionAttributesInternal(installing_version, &installing_version_);
78 mask.add(ChangedVersionAttributesMask::INSTALLING_VERSION);
80 if (waiting_version != waiting_version_) {
81 SetVersionAttributesInternal(waiting_version, &waiting_version_);
82 mask.add(ChangedVersionAttributesMask::WAITING_VERSION);
84 if (active_version != active_version_) {
85 SetVersionAttributesInternal(active_version, &active_version_);
86 mask.add(ChangedVersionAttributesMask::ACTIVE_VERSION);
89 if (!dispatcher_host_)
90 return; // Could be NULL in some tests.
94 ServiceWorkerVersionAttributes attributes;
95 if (mask.installing_changed())
96 attributes.installing = CreateHandleAndPass(installing_version);
97 if (mask.waiting_changed())
98 attributes.waiting = CreateHandleAndPass(waiting_version);
99 if (mask.active_changed())
100 attributes.active = CreateHandleAndPass(active_version);
102 dispatcher_host_->Send(new ServiceWorkerMsg_SetVersionAttributes(
103 kDocumentMainThreadId,
105 kInvalidServiceWorkerRegistrationHandleId,
110 void ServiceWorkerProviderHost::SetVersionAttributesInternal(
111 ServiceWorkerVersion* version,
112 scoped_refptr<ServiceWorkerVersion>* data_member) {
113 scoped_refptr<ServiceWorkerVersion> previous_version = *data_member;
114 *data_member = version;
116 version->AddPotentialControllee(this);
117 if (previous_version)
118 previous_version->RemovePotentialControllee(this);
121 void ServiceWorkerProviderHost::SetControllerVersionAttribute(
122 ServiceWorkerVersion* version) {
123 if (version == controlling_version_)
126 scoped_refptr<ServiceWorkerVersion> previous_version = controlling_version_;
127 controlling_version_ = version;
129 version->AddControllee(this);
130 if (previous_version)
131 previous_version->RemoveControllee(this);
133 if (!dispatcher_host_)
134 return; // Could be NULL in some tests.
136 dispatcher_host_->Send(new ServiceWorkerMsg_SetControllerServiceWorker(
137 kDocumentMainThreadId, provider_id(), CreateHandleAndPass(version)));
140 void ServiceWorkerProviderHost::ClearVersionAttributes() {
141 SetVersionAttributes(NULL, NULL, NULL);
142 SetControllerVersionAttribute(NULL);
145 bool ServiceWorkerProviderHost::SetHostedVersionId(int64 version_id) {
147 return true; // System is shutting down.
149 return false; // Unexpected bad message.
151 ServiceWorkerVersion* live_version = context_->GetLiveVersion(version_id);
153 return true; // Was deleted before it got started.
155 ServiceWorkerVersionInfo info = live_version->GetInfo();
156 if (info.running_status != ServiceWorkerVersion::STARTING ||
157 info.process_id != process_id_) {
158 // If we aren't trying to start this version in our process
159 // something is amiss.
163 running_hosted_version_ = live_version;
167 void ServiceWorkerProviderHost::AssociateRegistration(
168 ServiceWorkerRegistration* registration) {
169 DCHECK(CanAssociateRegistration(registration));
170 associated_registration_ = registration;
171 registration->AddListener(this);
172 SetVersionAttributes(registration->installing_version(),
173 registration->waiting_version(),
174 registration->active_version());
175 SetControllerVersionAttribute(registration->active_version());
178 void ServiceWorkerProviderHost::UnassociateRegistration() {
179 if (!associated_registration_)
181 associated_registration_->RemoveListener(this);
182 associated_registration_ = NULL;
183 ClearVersionAttributes();
186 scoped_ptr<ServiceWorkerRequestHandler>
187 ServiceWorkerProviderHost::CreateRequestHandler(
188 ResourceType resource_type,
189 base::WeakPtr<webkit_blob::BlobStorageContext> blob_storage_context) {
190 if (IsHostToRunningServiceWorker()) {
191 return scoped_ptr<ServiceWorkerRequestHandler>(
192 new ServiceWorkerContextRequestHandler(
193 context_, AsWeakPtr(), blob_storage_context, resource_type));
195 if (ServiceWorkerUtils::IsMainResourceType(resource_type) ||
197 return scoped_ptr<ServiceWorkerRequestHandler>(
198 new ServiceWorkerControlleeRequestHandler(
199 context_, AsWeakPtr(), blob_storage_context, resource_type));
201 return scoped_ptr<ServiceWorkerRequestHandler>();
204 bool ServiceWorkerProviderHost::CanAssociateRegistration(
205 ServiceWorkerRegistration* registration) {
208 if (running_hosted_version_)
210 if (!registration || associated_registration_)
215 void ServiceWorkerProviderHost::PostMessage(
216 const base::string16& message,
217 const std::vector<int>& sent_message_port_ids) {
218 if (!dispatcher_host_)
219 return; // Could be NULL in some tests.
221 std::vector<int> new_routing_ids;
222 dispatcher_host_->message_port_message_filter()->
223 UpdateMessagePortsWithNewRoutes(sent_message_port_ids,
226 dispatcher_host_->Send(
227 new ServiceWorkerMsg_MessageToDocument(
228 kDocumentMainThreadId, provider_id(),
230 sent_message_port_ids,
234 ServiceWorkerObjectInfo ServiceWorkerProviderHost::CreateHandleAndPass(
235 ServiceWorkerVersion* version) {
236 ServiceWorkerObjectInfo info;
237 if (context_ && version) {
238 scoped_ptr<ServiceWorkerHandle> handle =
239 ServiceWorkerHandle::Create(context_,
241 kDocumentMainThreadId,
244 info = handle->GetObjectInfo();
245 dispatcher_host_->RegisterServiceWorkerHandle(handle.Pass());
250 bool ServiceWorkerProviderHost::IsContextAlive() {
251 return context_ != NULL;
254 } // namespace content