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/resource_request_body.h"
18 #include "content/common/service_worker/service_worker_messages.h"
22 static const int kDocumentMainThreadId
= 0;
24 ServiceWorkerProviderHost::ServiceWorkerProviderHost(
25 int process_id
, int provider_id
,
26 base::WeakPtr
<ServiceWorkerContextCore
> context
,
27 ServiceWorkerDispatcherHost
* dispatcher_host
)
28 : process_id_(process_id
),
29 provider_id_(provider_id
),
31 dispatcher_host_(dispatcher_host
) {
34 ServiceWorkerProviderHost::~ServiceWorkerProviderHost() {
35 // Clear docurl so the deferred activation of a waiting worker
36 // won't associate the new version with a provider being destroyed.
37 document_url_
= GURL();
38 if (controlling_version_
.get())
39 controlling_version_
->RemoveControllee(this);
40 if (active_version_
.get())
41 active_version_
->RemovePotentialControllee(this);
42 if (waiting_version_
.get())
43 waiting_version_
->RemovePotentialControllee(this);
44 if (installing_version_
.get())
45 installing_version_
->RemovePotentialControllee(this);
46 if (associated_registration_
.get())
47 associated_registration_
->RemoveListener(this);
50 void ServiceWorkerProviderHost::OnVersionAttributesChanged(
51 ServiceWorkerRegistration
* registration
,
52 ChangedVersionAttributesMask changed_mask
,
53 const ServiceWorkerRegistrationInfo
& info
) {
54 DCHECK_EQ(associated_registration_
.get(), registration
);
55 UpdatePotentialControllees(registration
->installing_version(),
56 registration
->waiting_version(),
57 registration
->active_version());
60 void ServiceWorkerProviderHost::OnRegistrationFailed(
61 ServiceWorkerRegistration
* registration
) {
62 DCHECK_EQ(associated_registration_
.get(), registration
);
63 UnassociateRegistration();
66 void ServiceWorkerProviderHost::SetDocumentUrl(const GURL
& url
) {
67 DCHECK(!url
.has_ref());
71 void ServiceWorkerProviderHost::UpdatePotentialControllees(
72 ServiceWorkerVersion
* installing_version
,
73 ServiceWorkerVersion
* waiting_version
,
74 ServiceWorkerVersion
* active_version
) {
75 if (installing_version
!= installing_version_
.get()) {
76 scoped_refptr
<ServiceWorkerVersion
> previous_version
= installing_version_
;
78 previous_version
->RemovePotentialControllee(this);
79 if (installing_version
)
80 installing_version
->AddPotentialControllee(this);
81 installing_version_
= installing_version
;
84 if (waiting_version
!= waiting_version_
.get()) {
85 scoped_refptr
<ServiceWorkerVersion
> previous_version
= waiting_version_
;
87 previous_version
->RemovePotentialControllee(this);
89 waiting_version
->AddPotentialControllee(this);
90 waiting_version_
= waiting_version
;
93 if (active_version
!= active_version_
.get()) {
94 scoped_refptr
<ServiceWorkerVersion
> previous_version
= active_version_
;
96 previous_version
->RemovePotentialControllee(this);
98 active_version
->AddPotentialControllee(this);
99 active_version_
= active_version
;
103 void ServiceWorkerProviderHost::SetControllerVersionAttribute(
104 ServiceWorkerVersion
* version
) {
105 if (version
== controlling_version_
.get())
108 scoped_refptr
<ServiceWorkerVersion
> previous_version
= controlling_version_
;
109 controlling_version_
= version
;
111 version
->AddControllee(this);
112 if (previous_version
.get())
113 previous_version
->RemoveControllee(this);
115 if (!dispatcher_host_
)
116 return; // Could be NULL in some tests.
118 dispatcher_host_
->Send(new ServiceWorkerMsg_SetControllerServiceWorker(
119 kDocumentMainThreadId
, provider_id(), CreateHandleAndPass(version
)));
122 bool ServiceWorkerProviderHost::SetHostedVersionId(int64 version_id
) {
124 return true; // System is shutting down.
125 if (active_version_
.get())
126 return false; // Unexpected bad message.
128 ServiceWorkerVersion
* live_version
= context_
->GetLiveVersion(version_id
);
130 return true; // Was deleted before it got started.
132 ServiceWorkerVersionInfo info
= live_version
->GetInfo();
133 if (info
.running_status
!= ServiceWorkerVersion::STARTING
||
134 info
.process_id
!= process_id_
) {
135 // If we aren't trying to start this version in our process
136 // something is amiss.
140 running_hosted_version_
= live_version
;
144 void ServiceWorkerProviderHost::AssociateRegistration(
145 ServiceWorkerRegistration
* registration
) {
146 DCHECK(CanAssociateRegistration(registration
));
147 associated_registration_
= registration
;
148 registration
->AddListener(this);
149 UpdatePotentialControllees(registration
->installing_version(),
150 registration
->waiting_version(),
151 registration
->active_version());
152 SetControllerVersionAttribute(registration
->active_version());
155 void ServiceWorkerProviderHost::UnassociateRegistration() {
156 if (!associated_registration_
.get())
158 associated_registration_
->RemoveListener(this);
159 associated_registration_
= NULL
;
160 UpdatePotentialControllees(NULL
, NULL
, NULL
);
161 SetControllerVersionAttribute(NULL
);
164 scoped_ptr
<ServiceWorkerRequestHandler
>
165 ServiceWorkerProviderHost::CreateRequestHandler(
166 ResourceType resource_type
,
167 base::WeakPtr
<storage::BlobStorageContext
> blob_storage_context
,
168 scoped_refptr
<ResourceRequestBody
> body
) {
169 if (IsHostToRunningServiceWorker()) {
170 return scoped_ptr
<ServiceWorkerRequestHandler
>(
171 new ServiceWorkerContextRequestHandler(
172 context_
, AsWeakPtr(), blob_storage_context
, resource_type
));
174 if (ServiceWorkerUtils::IsMainResourceType(resource_type
) ||
176 return scoped_ptr
<ServiceWorkerRequestHandler
>(
177 new ServiceWorkerControlleeRequestHandler(
178 context_
, AsWeakPtr(), blob_storage_context
, resource_type
, body
));
180 return scoped_ptr
<ServiceWorkerRequestHandler
>();
183 bool ServiceWorkerProviderHost::CanAssociateRegistration(
184 ServiceWorkerRegistration
* registration
) {
187 if (running_hosted_version_
.get())
189 if (!registration
|| associated_registration_
.get())
194 void ServiceWorkerProviderHost::PostMessage(
195 const base::string16
& message
,
196 const std::vector
<int>& sent_message_port_ids
) {
197 if (!dispatcher_host_
)
198 return; // Could be NULL in some tests.
200 std::vector
<int> new_routing_ids
;
201 dispatcher_host_
->message_port_message_filter()->
202 UpdateMessagePortsWithNewRoutes(sent_message_port_ids
,
205 dispatcher_host_
->Send(
206 new ServiceWorkerMsg_MessageToDocument(
207 kDocumentMainThreadId
, provider_id(),
209 sent_message_port_ids
,
213 ServiceWorkerObjectInfo
ServiceWorkerProviderHost::CreateHandleAndPass(
214 ServiceWorkerVersion
* version
) {
215 ServiceWorkerObjectInfo info
;
216 if (context_
&& version
) {
217 scoped_ptr
<ServiceWorkerHandle
> handle
=
218 ServiceWorkerHandle::Create(context_
,
220 kDocumentMainThreadId
,
223 info
= handle
->GetObjectInfo();
224 dispatcher_host_
->RegisterServiceWorkerHandle(handle
.Pass());
229 bool ServiceWorkerProviderHost::IsContextAlive() {
230 return context_
!= NULL
;
233 } // namespace content