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"
19 #include "content/common/service_worker/service_worker_types.h"
23 static const int kDocumentMainThreadId
= 0;
25 ServiceWorkerProviderHost::ServiceWorkerProviderHost(
26 int process_id
, int provider_id
,
27 base::WeakPtr
<ServiceWorkerContextCore
> context
,
28 ServiceWorkerDispatcherHost
* dispatcher_host
)
29 : process_id_(process_id
),
30 provider_id_(provider_id
),
32 dispatcher_host_(dispatcher_host
),
33 allow_association_(true) {
36 ServiceWorkerProviderHost::~ServiceWorkerProviderHost() {
37 // Clear docurl so the deferred activation of a waiting worker
38 // won't associate the new version with a provider being destroyed.
39 document_url_
= GURL();
40 if (controlling_version_
.get())
41 controlling_version_
->RemoveControllee(this);
42 if (associated_registration_
.get()) {
43 DecreaseProcessReference(associated_registration_
->pattern());
44 associated_registration_
->RemoveListener(this);
46 for (std::vector
<GURL
>::iterator it
= associated_patterns_
.begin();
47 it
!= associated_patterns_
.end(); ++it
) {
48 DecreaseProcessReference(*it
);
52 void ServiceWorkerProviderHost::OnRegistrationFailed(
53 ServiceWorkerRegistration
* registration
) {
54 DCHECK_EQ(associated_registration_
.get(), registration
);
55 DisassociateRegistration();
58 void ServiceWorkerProviderHost::SetDocumentUrl(const GURL
& url
) {
59 DCHECK(!url
.has_ref());
63 void ServiceWorkerProviderHost::SetTopmostFrameUrl(const GURL
& url
) {
64 topmost_frame_url_
= url
;
67 void ServiceWorkerProviderHost::SetControllerVersionAttribute(
68 ServiceWorkerVersion
* version
) {
69 if (version
== controlling_version_
.get())
72 scoped_refptr
<ServiceWorkerVersion
> previous_version
= controlling_version_
;
73 controlling_version_
= version
;
75 version
->AddControllee(this);
76 if (previous_version
.get())
77 previous_version
->RemoveControllee(this);
79 if (!dispatcher_host_
)
80 return; // Could be NULL in some tests.
82 dispatcher_host_
->Send(new ServiceWorkerMsg_SetControllerServiceWorker(
83 kDocumentMainThreadId
, provider_id(), CreateHandleAndPass(version
)));
86 bool ServiceWorkerProviderHost::SetHostedVersionId(int64 version_id
) {
88 return true; // System is shutting down.
90 return false; // Unexpected bad message.
92 ServiceWorkerVersion
* live_version
= context_
->GetLiveVersion(version_id
);
94 return true; // Was deleted before it got started.
96 ServiceWorkerVersionInfo info
= live_version
->GetInfo();
97 if (info
.running_status
!= ServiceWorkerVersion::STARTING
||
98 info
.process_id
!= process_id_
) {
99 // If we aren't trying to start this version in our process
100 // something is amiss.
104 running_hosted_version_
= live_version
;
108 void ServiceWorkerProviderHost::AssociateRegistration(
109 ServiceWorkerRegistration
* registration
) {
110 DCHECK(CanAssociateRegistration(registration
));
111 if (associated_registration_
.get())
112 DecreaseProcessReference(associated_registration_
->pattern());
113 IncreaseProcessReference(registration
->pattern());
115 if (dispatcher_host_
) {
116 ServiceWorkerRegistrationHandle
* handle
=
117 dispatcher_host_
->GetOrCreateRegistrationHandle(
118 provider_id(), registration
);
120 ServiceWorkerVersionAttributes attrs
;
121 attrs
.installing
= handle
->CreateServiceWorkerHandleAndPass(
122 registration
->installing_version());
123 attrs
.waiting
= handle
->CreateServiceWorkerHandleAndPass(
124 registration
->waiting_version());
125 attrs
.active
= handle
->CreateServiceWorkerHandleAndPass(
126 registration
->active_version());
128 dispatcher_host_
->Send(new ServiceWorkerMsg_AssociateRegistration(
129 kDocumentMainThreadId
, provider_id(), handle
->GetObjectInfo(), attrs
));
132 associated_registration_
= registration
;
133 associated_registration_
->AddListener(this);
134 SetControllerVersionAttribute(registration
->active_version());
137 void ServiceWorkerProviderHost::DisassociateRegistration() {
138 if (!associated_registration_
.get())
140 DecreaseProcessReference(associated_registration_
->pattern());
141 associated_registration_
->RemoveListener(this);
142 associated_registration_
= NULL
;
143 SetControllerVersionAttribute(NULL
);
145 if (dispatcher_host_
) {
146 dispatcher_host_
->Send(new ServiceWorkerMsg_DisassociateRegistration(
147 kDocumentMainThreadId
, provider_id()));
151 scoped_ptr
<ServiceWorkerRequestHandler
>
152 ServiceWorkerProviderHost::CreateRequestHandler(
153 FetchRequestMode request_mode
,
154 FetchCredentialsMode credentials_mode
,
155 ResourceType resource_type
,
156 RequestContextType request_context_type
,
157 RequestContextFrameType frame_type
,
158 base::WeakPtr
<storage::BlobStorageContext
> blob_storage_context
,
159 scoped_refptr
<ResourceRequestBody
> body
) {
160 if (IsHostToRunningServiceWorker()) {
161 return scoped_ptr
<ServiceWorkerRequestHandler
>(
162 new ServiceWorkerContextRequestHandler(
163 context_
, AsWeakPtr(), blob_storage_context
, resource_type
));
165 if (ServiceWorkerUtils::IsMainResourceType(resource_type
) ||
166 controlling_version()) {
167 return scoped_ptr
<ServiceWorkerRequestHandler
>(
168 new ServiceWorkerControlleeRequestHandler(context_
,
170 blob_storage_context
,
174 request_context_type
,
178 return scoped_ptr
<ServiceWorkerRequestHandler
>();
181 bool ServiceWorkerProviderHost::CanAssociateRegistration(
182 ServiceWorkerRegistration
* registration
) {
185 if (running_hosted_version_
.get())
187 if (!registration
|| associated_registration_
.get() || !allow_association_
)
192 void ServiceWorkerProviderHost::PostMessage(
193 const base::string16
& message
,
194 const std::vector
<int>& sent_message_port_ids
) {
195 if (!dispatcher_host_
)
196 return; // Could be NULL in some tests.
198 std::vector
<int> new_routing_ids
;
199 dispatcher_host_
->message_port_message_filter()->
200 UpdateMessagePortsWithNewRoutes(sent_message_port_ids
,
203 dispatcher_host_
->Send(
204 new ServiceWorkerMsg_MessageToDocument(
205 kDocumentMainThreadId
, provider_id(),
207 sent_message_port_ids
,
211 void ServiceWorkerProviderHost::AddScopedProcessReferenceToPattern(
212 const GURL
& pattern
) {
213 associated_patterns_
.push_back(pattern
);
214 IncreaseProcessReference(pattern
);
217 ServiceWorkerObjectInfo
ServiceWorkerProviderHost::CreateHandleAndPass(
218 ServiceWorkerVersion
* version
) {
219 ServiceWorkerObjectInfo info
;
220 if (context_
&& version
) {
221 scoped_ptr
<ServiceWorkerHandle
> handle
=
222 ServiceWorkerHandle::Create(context_
,
224 kDocumentMainThreadId
,
227 info
= handle
->GetObjectInfo();
228 dispatcher_host_
->RegisterServiceWorkerHandle(handle
.Pass());
233 void ServiceWorkerProviderHost::IncreaseProcessReference(
234 const GURL
& pattern
) {
235 if (context_
&& context_
->process_manager()) {
236 context_
->process_manager()->AddProcessReferenceToPattern(
237 pattern
, process_id_
);
241 void ServiceWorkerProviderHost::DecreaseProcessReference(
242 const GURL
& pattern
) {
243 if (context_
&& context_
->process_manager()) {
244 context_
->process_manager()->RemoveProcessReferenceFromPattern(
245 pattern
, process_id_
);
249 bool ServiceWorkerProviderHost::IsContextAlive() {
250 return context_
!= NULL
;
253 } // namespace content