service_worker_provider_host.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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 allow_association_(true) { 33} 34 35ServiceWorkerProviderHost::~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 51void ServiceWorkerProviderHost::OnRegistrationFailed( 52 ServiceWorkerRegistration* registration) { 53 DCHECK_EQ(associated_registration_.get(), registration); 54 DisassociateRegistration(); 55} 56 57void ServiceWorkerProviderHost::SetDocumentUrl(const GURL& url) { 58 DCHECK(!url.has_ref()); 59 document_url_ = url; 60} 61 62void 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 81bool 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 103void 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 132void 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 146scoped_ptr<ServiceWorkerRequestHandler> 147ServiceWorkerProviderHost::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 165bool 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 176void 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 195void ServiceWorkerProviderHost::AddScopedProcessReferenceToPattern( 196 const GURL& pattern) { 197 associated_patterns_.push_back(pattern); 198 IncreaseProcessReference(pattern); 199} 200 201ServiceWorkerObjectInfo 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 217void ServiceWorkerProviderHost::IncreaseProcessReference( 218 const GURL& pattern) { 219 if (context_ && context_->process_manager()) { 220 context_->process_manager()->AddProcessReferenceToPattern( 221 pattern, process_id_); 222 } 223} 224 225void ServiceWorkerProviderHost::DecreaseProcessReference( 226 const GURL& pattern) { 227 if (context_ && context_->process_manager()) { 228 context_->process_manager()->RemoveProcessReferenceFromPattern( 229 pattern, process_id_); 230 } 231} 232 233bool ServiceWorkerProviderHost::IsContextAlive() { 234 return context_ != NULL; 235} 236 237} // namespace content 238