Upstream version 10.39.225.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/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
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
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
51 void ServiceWorkerProviderHost::OnRegistrationFailed(
52     ServiceWorkerRegistration* registration) {
53   DCHECK_EQ(associated_registration_.get(), registration);
54   DisassociateRegistration();
55 }
56
57 void ServiceWorkerProviderHost::SetDocumentUrl(const GURL& url) {
58   DCHECK(!url.has_ref());
59   document_url_ = url;
60 }
61
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
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
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
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>
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
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
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
195 void ServiceWorkerProviderHost::AddScopedProcessReferenceToPattern(
196     const GURL& pattern) {
197   associated_patterns_.push_back(pattern);
198   IncreaseProcessReference(pattern);
199 }
200
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
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
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
233 bool ServiceWorkerProviderHost::IsContextAlive() {
234   return context_ != NULL;
235 }
236
237 }  // namespace content