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.
4
5 #include "content/browser/service_worker/service_worker_provider_host.h"
6
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
20 namespace content {
21
22 static const int kDocumentMainThreadId = 0;
23
ServiceWorkerProviderHost(int process_id,int provider_id,base::WeakPtr<ServiceWorkerContextCore> context,ServiceWorkerDispatcherHost * dispatcher_host)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),
30 context_(context),
31 dispatcher_host_(dispatcher_host),
32 allow_association_(true) {
33 }
34
~ServiceWorkerProviderHost()35 ServiceWorkerProviderHost::~ServiceWorkerProviderHost() {
36 // Clear docurl so the deferred activation of a waiting worker
37 // won't associate the new version with a provider being destroyed.
38 document_url_ = GURL();
39 if (controlling_version_.get())
40 controlling_version_->RemoveControllee(this);
41 if (associated_registration_.get()) {
42 DecreaseProcessReference(associated_registration_->pattern());
43 associated_registration_->RemoveListener(this);
44 }
45 for (std::vector<GURL>::iterator it = associated_patterns_.begin();
46 it != associated_patterns_.end(); ++it) {
47 DecreaseProcessReference(*it);
48 }
49 }
50
OnRegistrationFailed(ServiceWorkerRegistration * registration)51 void ServiceWorkerProviderHost::OnRegistrationFailed(
52 ServiceWorkerRegistration* registration) {
53 DCHECK_EQ(associated_registration_.get(), registration);
54 DisassociateRegistration();
55 }
56
SetDocumentUrl(const GURL & url)57 void ServiceWorkerProviderHost::SetDocumentUrl(const GURL& url) {
58 DCHECK(!url.has_ref());
59 document_url_ = url;
60 }
61
SetControllerVersionAttribute(ServiceWorkerVersion * version)62 void ServiceWorkerProviderHost::SetControllerVersionAttribute(
63 ServiceWorkerVersion* version) {
64 if (version == controlling_version_.get())
65 return;
66
67 scoped_refptr<ServiceWorkerVersion> previous_version = controlling_version_;
68 controlling_version_ = version;
69 if (version)
70 version->AddControllee(this);
71 if (previous_version.get())
72 previous_version->RemoveControllee(this);
73
74 if (!dispatcher_host_)
75 return; // Could be NULL in some tests.
76
77 dispatcher_host_->Send(new ServiceWorkerMsg_SetControllerServiceWorker(
78 kDocumentMainThreadId, provider_id(), CreateHandleAndPass(version)));
79 }
80
SetHostedVersionId(int64 version_id)81 bool ServiceWorkerProviderHost::SetHostedVersionId(int64 version_id) {
82 if (!context_)
83 return true; // System is shutting down.
84 if (active_version())
85 return false; // Unexpected bad message.
86
87 ServiceWorkerVersion* live_version = context_->GetLiveVersion(version_id);
88 if (!live_version)
89 return true; // Was deleted before it got started.
90
91 ServiceWorkerVersionInfo info = live_version->GetInfo();
92 if (info.running_status != ServiceWorkerVersion::STARTING ||
93 info.process_id != process_id_) {
94 // If we aren't trying to start this version in our process
95 // something is amiss.
96 return false;
97 }
98
99 running_hosted_version_ = live_version;
100 return true;
101 }
102
AssociateRegistration(ServiceWorkerRegistration * registration)103 void ServiceWorkerProviderHost::AssociateRegistration(
104 ServiceWorkerRegistration* registration) {
105 DCHECK(CanAssociateRegistration(registration));
106 if (associated_registration_.get())
107 DecreaseProcessReference(associated_registration_->pattern());
108 IncreaseProcessReference(registration->pattern());
109
110 if (dispatcher_host_) {
111 ServiceWorkerRegistrationHandle* handle =
112 dispatcher_host_->GetOrCreateRegistrationHandle(
113 provider_id(), registration);
114
115 ServiceWorkerVersionAttributes attrs;
116 attrs.installing = handle->CreateServiceWorkerHandleAndPass(
117 registration->installing_version());
118 attrs.waiting = handle->CreateServiceWorkerHandleAndPass(
119 registration->waiting_version());
120 attrs.active = handle->CreateServiceWorkerHandleAndPass(
121 registration->active_version());
122
123 dispatcher_host_->Send(new ServiceWorkerMsg_AssociateRegistration(
124 kDocumentMainThreadId, provider_id(), handle->GetObjectInfo(), attrs));
125 }
126
127 associated_registration_ = registration;
128 associated_registration_->AddListener(this);
129 SetControllerVersionAttribute(registration->active_version());
130 }
131
DisassociateRegistration()132 void ServiceWorkerProviderHost::DisassociateRegistration() {
133 if (!associated_registration_.get())
134 return;
135 DecreaseProcessReference(associated_registration_->pattern());
136 associated_registration_->RemoveListener(this);
137 associated_registration_ = NULL;
138 SetControllerVersionAttribute(NULL);
139
140 if (dispatcher_host_) {
141 dispatcher_host_->Send(new ServiceWorkerMsg_DisassociateRegistration(
142 kDocumentMainThreadId, provider_id()));
143 }
144 }
145
146 scoped_ptr<ServiceWorkerRequestHandler>
CreateRequestHandler(ResourceType resource_type,base::WeakPtr<storage::BlobStorageContext> blob_storage_context,scoped_refptr<ResourceRequestBody> body)147 ServiceWorkerProviderHost::CreateRequestHandler(
148 ResourceType resource_type,
149 base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
150 scoped_refptr<ResourceRequestBody> body) {
151 if (IsHostToRunningServiceWorker()) {
152 return scoped_ptr<ServiceWorkerRequestHandler>(
153 new ServiceWorkerContextRequestHandler(
154 context_, AsWeakPtr(), blob_storage_context, resource_type));
155 }
156 if (ServiceWorkerUtils::IsMainResourceType(resource_type) ||
157 controlling_version()) {
158 return scoped_ptr<ServiceWorkerRequestHandler>(
159 new ServiceWorkerControlleeRequestHandler(
160 context_, AsWeakPtr(), blob_storage_context, resource_type, body));
161 }
162 return scoped_ptr<ServiceWorkerRequestHandler>();
163 }
164
CanAssociateRegistration(ServiceWorkerRegistration * registration)165 bool ServiceWorkerProviderHost::CanAssociateRegistration(
166 ServiceWorkerRegistration* registration) {
167 if (!context_)
168 return false;
169 if (running_hosted_version_.get())
170 return false;
171 if (!registration || associated_registration_.get() || !allow_association_)
172 return false;
173 return true;
174 }
175
PostMessage(const base::string16 & message,const std::vector<int> & sent_message_port_ids)176 void ServiceWorkerProviderHost::PostMessage(
177 const base::string16& message,
178 const std::vector<int>& sent_message_port_ids) {
179 if (!dispatcher_host_)
180 return; // Could be NULL in some tests.
181
182 std::vector<int> new_routing_ids;
183 dispatcher_host_->message_port_message_filter()->
184 UpdateMessagePortsWithNewRoutes(sent_message_port_ids,
185 &new_routing_ids);
186
187 dispatcher_host_->Send(
188 new ServiceWorkerMsg_MessageToDocument(
189 kDocumentMainThreadId, provider_id(),
190 message,
191 sent_message_port_ids,
192 new_routing_ids));
193 }
194
AddScopedProcessReferenceToPattern(const GURL & pattern)195 void ServiceWorkerProviderHost::AddScopedProcessReferenceToPattern(
196 const GURL& pattern) {
197 associated_patterns_.push_back(pattern);
198 IncreaseProcessReference(pattern);
199 }
200
CreateHandleAndPass(ServiceWorkerVersion * version)201 ServiceWorkerObjectInfo ServiceWorkerProviderHost::CreateHandleAndPass(
202 ServiceWorkerVersion* version) {
203 ServiceWorkerObjectInfo info;
204 if (context_ && version) {
205 scoped_ptr<ServiceWorkerHandle> handle =
206 ServiceWorkerHandle::Create(context_,
207 dispatcher_host_,
208 kDocumentMainThreadId,
209 provider_id_,
210 version);
211 info = handle->GetObjectInfo();
212 dispatcher_host_->RegisterServiceWorkerHandle(handle.Pass());
213 }
214 return info;
215 }
216
IncreaseProcessReference(const GURL & pattern)217 void ServiceWorkerProviderHost::IncreaseProcessReference(
218 const GURL& pattern) {
219 if (context_ && context_->process_manager()) {
220 context_->process_manager()->AddProcessReferenceToPattern(
221 pattern, process_id_);
222 }
223 }
224
DecreaseProcessReference(const GURL & pattern)225 void ServiceWorkerProviderHost::DecreaseProcessReference(
226 const GURL& pattern) {
227 if (context_ && context_->process_manager()) {
228 context_->process_manager()->RemoveProcessReferenceFromPattern(
229 pattern, process_id_);
230 }
231 }
232
IsContextAlive()233 bool ServiceWorkerProviderHost::IsContextAlive() {
234 return context_ != NULL;
235 }
236
237 } // namespace content
238