Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / browser / service_worker / service_worker_provider_host.cc
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/service_worker/service_worker_messages.h"
18
19 namespace content {
20
21 static const int kDocumentMainThreadId = 0;
22
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),
29       context_(context),
30       dispatcher_host_(dispatcher_host) {
31 }
32
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);
39   if (active_version_)
40     active_version_->RemovePotentialControllee(this);
41   if (waiting_version_)
42     waiting_version_->RemovePotentialControllee(this);
43   if (installing_version_)
44     installing_version_->RemovePotentialControllee(this);
45   if (associated_registration_)
46     associated_registration_->RemoveListener(this);
47 }
48
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());
57 }
58
59 void ServiceWorkerProviderHost::OnRegistrationFailed(
60     ServiceWorkerRegistration* registration) {
61   DCHECK_EQ(associated_registration_, registration);
62   UnassociateRegistration();
63 }
64
65 void ServiceWorkerProviderHost::SetDocumentUrl(const GURL& url) {
66   DCHECK(!url.has_ref());
67   document_url_ = url;
68 }
69
70 void ServiceWorkerProviderHost::SetVersionAttributes(
71     ServiceWorkerVersion* installing_version,
72     ServiceWorkerVersion* waiting_version,
73     ServiceWorkerVersion* active_version) {
74   ChangedVersionAttributesMask mask;
75
76   if (installing_version != installing_version_) {
77     SetVersionAttributesInternal(installing_version, &installing_version_);
78     mask.add(ChangedVersionAttributesMask::INSTALLING_VERSION);
79   }
80   if (waiting_version != waiting_version_) {
81     SetVersionAttributesInternal(waiting_version, &waiting_version_);
82     mask.add(ChangedVersionAttributesMask::WAITING_VERSION);
83   }
84   if (active_version != active_version_) {
85     SetVersionAttributesInternal(active_version, &active_version_);
86     mask.add(ChangedVersionAttributesMask::ACTIVE_VERSION);
87   }
88
89   if (!dispatcher_host_)
90     return;  // Could be NULL in some tests.
91   if (!mask.changed())
92     return;
93
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);
101
102   dispatcher_host_->Send(new ServiceWorkerMsg_SetVersionAttributes(
103       kDocumentMainThreadId,
104       provider_id(),
105       kInvalidServiceWorkerRegistrationHandleId,
106       mask.changed(),
107       attributes));
108 }
109
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;
115   if (version)
116     version->AddPotentialControllee(this);
117   if (previous_version)
118     previous_version->RemovePotentialControllee(this);
119 }
120
121 void ServiceWorkerProviderHost::SetControllerVersionAttribute(
122     ServiceWorkerVersion* version) {
123   if (version == controlling_version_)
124     return;
125
126   scoped_refptr<ServiceWorkerVersion> previous_version = controlling_version_;
127   controlling_version_ = version;
128   if (version)
129     version->AddControllee(this);
130   if (previous_version)
131     previous_version->RemoveControllee(this);
132
133   if (!dispatcher_host_)
134     return;  // Could be NULL in some tests.
135
136   dispatcher_host_->Send(new ServiceWorkerMsg_SetControllerServiceWorker(
137       kDocumentMainThreadId, provider_id(), CreateHandleAndPass(version)));
138 }
139
140 void ServiceWorkerProviderHost::ClearVersionAttributes() {
141   SetVersionAttributes(NULL, NULL, NULL);
142   SetControllerVersionAttribute(NULL);
143 }
144
145 bool ServiceWorkerProviderHost::SetHostedVersionId(int64 version_id) {
146   if (!context_)
147     return true;  // System is shutting down.
148   if (active_version_)
149     return false;  // Unexpected bad message.
150
151   ServiceWorkerVersion* live_version = context_->GetLiveVersion(version_id);
152   if (!live_version)
153     return true;  // Was deleted before it got started.
154
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.
160     return false;
161   }
162
163   running_hosted_version_ = live_version;
164   return true;
165 }
166
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());
176 }
177
178 void ServiceWorkerProviderHost::UnassociateRegistration() {
179   if (!associated_registration_)
180     return;
181   associated_registration_->RemoveListener(this);
182   associated_registration_ = NULL;
183   ClearVersionAttributes();
184 }
185
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));
194   }
195   if (ServiceWorkerUtils::IsMainResourceType(resource_type) ||
196       active_version()) {
197     return scoped_ptr<ServiceWorkerRequestHandler>(
198         new ServiceWorkerControlleeRequestHandler(
199             context_, AsWeakPtr(), blob_storage_context, resource_type));
200   }
201   return scoped_ptr<ServiceWorkerRequestHandler>();
202 }
203
204 bool ServiceWorkerProviderHost::CanAssociateRegistration(
205     ServiceWorkerRegistration* registration) {
206   if (!context_)
207     return false;
208   if (running_hosted_version_)
209     return false;
210   if (!registration || associated_registration_)
211     return false;
212   return true;
213 }
214
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.
220
221   std::vector<int> new_routing_ids;
222   dispatcher_host_->message_port_message_filter()->
223       UpdateMessagePortsWithNewRoutes(sent_message_port_ids,
224                                       &new_routing_ids);
225
226   dispatcher_host_->Send(
227       new ServiceWorkerMsg_MessageToDocument(
228           kDocumentMainThreadId, provider_id(),
229           message,
230           sent_message_port_ids,
231           new_routing_ids));
232 }
233
234 ServiceWorkerObjectInfo ServiceWorkerProviderHost::CreateHandleAndPass(
235     ServiceWorkerVersion* version) {
236   ServiceWorkerObjectInfo info;
237   if (context_ && version) {
238     scoped_ptr<ServiceWorkerHandle> handle =
239         ServiceWorkerHandle::Create(context_,
240                                     dispatcher_host_,
241                                     kDocumentMainThreadId,
242                                     provider_id_,
243                                     version);
244     info = handle->GetObjectInfo();
245     dispatcher_host_->RegisterServiceWorkerHandle(handle.Pass());
246   }
247   return info;
248 }
249
250 bool ServiceWorkerProviderHost::IsContextAlive() {
251   return context_ != NULL;
252 }
253
254 }  // namespace content