service_worker_provider_host.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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
20namespace content {
21
22static const int kDocumentMainThreadId = 0;
23
24ServiceWorkerProviderHost::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}
33
34ServiceWorkerProviderHost::~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_)
39    controlling_version_->RemoveControllee(this);
40  if (active_version_)
41    active_version_->RemovePotentialControllee(this);
42  if (waiting_version_)
43    waiting_version_->RemovePotentialControllee(this);
44  if (installing_version_)
45    installing_version_->RemovePotentialControllee(this);
46  if (associated_registration_)
47    associated_registration_->RemoveListener(this);
48}
49
50void ServiceWorkerProviderHost::OnVersionAttributesChanged(
51    ServiceWorkerRegistration* registration,
52    ChangedVersionAttributesMask changed_mask,
53    const ServiceWorkerRegistrationInfo& info) {
54  DCHECK_EQ(associated_registration_, registration);
55  SetVersionAttributes(registration->installing_version(),
56                       registration->waiting_version(),
57                       registration->active_version());
58}
59
60void ServiceWorkerProviderHost::OnRegistrationFailed(
61    ServiceWorkerRegistration* registration) {
62  DCHECK_EQ(associated_registration_, registration);
63  UnassociateRegistration();
64}
65
66void ServiceWorkerProviderHost::SetDocumentUrl(const GURL& url) {
67  DCHECK(!url.has_ref());
68  document_url_ = url;
69}
70
71void ServiceWorkerProviderHost::SetVersionAttributes(
72    ServiceWorkerVersion* installing_version,
73    ServiceWorkerVersion* waiting_version,
74    ServiceWorkerVersion* active_version) {
75  ChangedVersionAttributesMask mask;
76
77  if (installing_version != installing_version_) {
78    SetVersionAttributesInternal(installing_version, &installing_version_);
79    mask.add(ChangedVersionAttributesMask::INSTALLING_VERSION);
80  }
81  if (waiting_version != waiting_version_) {
82    SetVersionAttributesInternal(waiting_version, &waiting_version_);
83    mask.add(ChangedVersionAttributesMask::WAITING_VERSION);
84  }
85  if (active_version != active_version_) {
86    SetVersionAttributesInternal(active_version, &active_version_);
87    mask.add(ChangedVersionAttributesMask::ACTIVE_VERSION);
88  }
89
90  if (!dispatcher_host_)
91    return;  // Could be NULL in some tests.
92  if (!mask.changed())
93    return;
94
95  ServiceWorkerVersionAttributes attributes;
96  if (mask.installing_changed())
97    attributes.installing = CreateHandleAndPass(installing_version);
98  if (mask.waiting_changed())
99    attributes.waiting = CreateHandleAndPass(waiting_version);
100  if (mask.active_changed())
101    attributes.active = CreateHandleAndPass(active_version);
102
103  dispatcher_host_->Send(new ServiceWorkerMsg_SetVersionAttributes(
104      kDocumentMainThreadId,
105      provider_id(),
106      kInvalidServiceWorkerRegistrationHandleId,
107      mask.changed(),
108      attributes));
109}
110
111void ServiceWorkerProviderHost::SetVersionAttributesInternal(
112    ServiceWorkerVersion* version,
113    scoped_refptr<ServiceWorkerVersion>* data_member) {
114  scoped_refptr<ServiceWorkerVersion> previous_version = *data_member;
115  *data_member = version;
116  if (version)
117    version->AddPotentialControllee(this);
118  if (previous_version)
119    previous_version->RemovePotentialControllee(this);
120}
121
122void ServiceWorkerProviderHost::SetControllerVersionAttribute(
123    ServiceWorkerVersion* version) {
124  if (version == controlling_version_)
125    return;
126
127  scoped_refptr<ServiceWorkerVersion> previous_version = controlling_version_;
128  controlling_version_ = version;
129  if (version)
130    version->AddControllee(this);
131  if (previous_version)
132    previous_version->RemoveControllee(this);
133
134  if (!dispatcher_host_)
135    return;  // Could be NULL in some tests.
136
137  dispatcher_host_->Send(new ServiceWorkerMsg_SetControllerServiceWorker(
138      kDocumentMainThreadId, provider_id(), CreateHandleAndPass(version)));
139}
140
141void ServiceWorkerProviderHost::ClearVersionAttributes() {
142  SetVersionAttributes(NULL, NULL, NULL);
143  SetControllerVersionAttribute(NULL);
144}
145
146bool ServiceWorkerProviderHost::SetHostedVersionId(int64 version_id) {
147  if (!context_)
148    return true;  // System is shutting down.
149  if (active_version_)
150    return false;  // Unexpected bad message.
151
152  ServiceWorkerVersion* live_version = context_->GetLiveVersion(version_id);
153  if (!live_version)
154    return true;  // Was deleted before it got started.
155
156  ServiceWorkerVersionInfo info = live_version->GetInfo();
157  if (info.running_status != ServiceWorkerVersion::STARTING ||
158      info.process_id != process_id_) {
159    // If we aren't trying to start this version in our process
160    // something is amiss.
161    return false;
162  }
163
164  running_hosted_version_ = live_version;
165  return true;
166}
167
168void ServiceWorkerProviderHost::AssociateRegistration(
169    ServiceWorkerRegistration* registration) {
170  DCHECK(CanAssociateRegistration(registration));
171  associated_registration_ = registration;
172  registration->AddListener(this);
173  SetVersionAttributes(registration->installing_version(),
174                       registration->waiting_version(),
175                       registration->active_version());
176  SetControllerVersionAttribute(registration->active_version());
177}
178
179void ServiceWorkerProviderHost::UnassociateRegistration() {
180  if (!associated_registration_)
181    return;
182  associated_registration_->RemoveListener(this);
183  associated_registration_ = NULL;
184  ClearVersionAttributes();
185}
186
187scoped_ptr<ServiceWorkerRequestHandler>
188ServiceWorkerProviderHost::CreateRequestHandler(
189    ResourceType resource_type,
190    base::WeakPtr<storage::BlobStorageContext> blob_storage_context,
191    scoped_refptr<ResourceRequestBody> body) {
192  if (IsHostToRunningServiceWorker()) {
193    return scoped_ptr<ServiceWorkerRequestHandler>(
194        new ServiceWorkerContextRequestHandler(
195            context_, AsWeakPtr(), blob_storage_context, resource_type));
196  }
197  if (ServiceWorkerUtils::IsMainResourceType(resource_type) ||
198      active_version()) {
199    return scoped_ptr<ServiceWorkerRequestHandler>(
200        new ServiceWorkerControlleeRequestHandler(
201            context_, AsWeakPtr(), blob_storage_context, resource_type, body));
202  }
203  return scoped_ptr<ServiceWorkerRequestHandler>();
204}
205
206bool ServiceWorkerProviderHost::CanAssociateRegistration(
207    ServiceWorkerRegistration* registration) {
208  if (!context_)
209    return false;
210  if (running_hosted_version_)
211    return false;
212  if (!registration || associated_registration_)
213    return false;
214  return true;
215}
216
217void ServiceWorkerProviderHost::PostMessage(
218    const base::string16& message,
219    const std::vector<int>& sent_message_port_ids) {
220  if (!dispatcher_host_)
221    return;  // Could be NULL in some tests.
222
223  std::vector<int> new_routing_ids;
224  dispatcher_host_->message_port_message_filter()->
225      UpdateMessagePortsWithNewRoutes(sent_message_port_ids,
226                                      &new_routing_ids);
227
228  dispatcher_host_->Send(
229      new ServiceWorkerMsg_MessageToDocument(
230          kDocumentMainThreadId, provider_id(),
231          message,
232          sent_message_port_ids,
233          new_routing_ids));
234}
235
236ServiceWorkerObjectInfo ServiceWorkerProviderHost::CreateHandleAndPass(
237    ServiceWorkerVersion* version) {
238  ServiceWorkerObjectInfo info;
239  if (context_ && version) {
240    scoped_ptr<ServiceWorkerHandle> handle =
241        ServiceWorkerHandle::Create(context_,
242                                    dispatcher_host_,
243                                    kDocumentMainThreadId,
244                                    provider_id_,
245                                    version);
246    info = handle->GetObjectInfo();
247    dispatcher_host_->RegisterServiceWorkerHandle(handle.Pass());
248  }
249  return info;
250}
251
252bool ServiceWorkerProviderHost::IsContextAlive() {
253  return context_ != NULL;
254}
255
256}  // namespace content
257