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_utils.h" 15 #include "content/browser/service_worker/service_worker_version.h" 16 #include "content/common/service_worker/service_worker_messages.h" 17 18 namespace content { 19 20 static const int kDocumentMainThreadId = 0; 21 22 ServiceWorkerProviderHost::ServiceWorkerProviderHost( 23 int process_id, int provider_id, 24 base::WeakPtr<ServiceWorkerContextCore> context, 25 ServiceWorkerDispatcherHost* dispatcher_host) 26 : process_id_(process_id), 27 provider_id_(provider_id), 28 context_(context), 29 dispatcher_host_(dispatcher_host) { 30 } 31 32 ServiceWorkerProviderHost::~ServiceWorkerProviderHost() { 33 if (active_version_) 34 active_version_->RemoveControllee(this); 35 if (waiting_version_) 36 waiting_version_->RemoveWaitingControllee(this); 37 } 38 39 void ServiceWorkerProviderHost::SetDocumentUrl(const GURL& url) { 40 DCHECK(!url.has_ref()); 41 document_url_ = url; 42 } 43 44 void ServiceWorkerProviderHost::SetActiveVersion( 45 ServiceWorkerVersion* version) { 46 if (version == active_version_) 47 return; 48 scoped_refptr<ServiceWorkerVersion> previous_version = active_version_; 49 active_version_ = version; 50 if (version) 51 version->AddControllee(this); 52 if (previous_version) 53 previous_version->RemoveControllee(this); 54 55 if (!dispatcher_host_) 56 return; // Could be NULL in some tests. 57 58 dispatcher_host_->Send(new ServiceWorkerMsg_SetCurrentServiceWorker( 59 kDocumentMainThreadId, provider_id(), CreateHandleAndPass(version))); 60 } 61 62 void ServiceWorkerProviderHost::SetWaitingVersion( 63 ServiceWorkerVersion* version) { 64 DCHECK(ValidateVersionForAssociation(version)); 65 if (version == waiting_version_) 66 return; 67 scoped_refptr<ServiceWorkerVersion> previous_version = waiting_version_; 68 waiting_version_ = version; 69 if (version) 70 version->AddWaitingControllee(this); 71 if (previous_version) 72 previous_version->RemoveWaitingControllee(this); 73 74 if (!dispatcher_host_) 75 return; // Could be NULL in some tests. 76 77 dispatcher_host_->Send(new ServiceWorkerMsg_SetWaitingServiceWorker( 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 scoped_ptr<ServiceWorkerRequestHandler> 104 ServiceWorkerProviderHost::CreateRequestHandler( 105 ResourceType::Type resource_type, 106 base::WeakPtr<webkit_blob::BlobStorageContext> blob_storage_context) { 107 if (IsHostToRunningServiceWorker()) { 108 return scoped_ptr<ServiceWorkerRequestHandler>( 109 new ServiceWorkerContextRequestHandler( 110 context_, AsWeakPtr(), blob_storage_context, resource_type)); 111 } 112 if (ServiceWorkerUtils::IsMainResourceType(resource_type) || 113 active_version()) { 114 return scoped_ptr<ServiceWorkerRequestHandler>( 115 new ServiceWorkerControlleeRequestHandler( 116 context_, AsWeakPtr(), blob_storage_context, resource_type)); 117 } 118 return scoped_ptr<ServiceWorkerRequestHandler>(); 119 } 120 121 bool ServiceWorkerProviderHost::ValidateVersionForAssociation( 122 ServiceWorkerVersion* version) { 123 if (running_hosted_version_) 124 return false; 125 if (!version) 126 return true; 127 128 // A version to be associated with this provider should have the same 129 // registration (scope) as current active/waiting versions. 130 if (active_version_) { 131 if (active_version_->registration_id() != version->registration_id()) 132 return false; 133 DCHECK_EQ(active_version_->scope(), version->scope()); 134 } 135 if (waiting_version_) { 136 if (waiting_version_->registration_id() != version->registration_id()) 137 return false; 138 DCHECK_EQ(waiting_version_->scope(), version->scope()); 139 } 140 return true; 141 } 142 143 void ServiceWorkerProviderHost::PostMessage( 144 const base::string16& message, 145 const std::vector<int>& sent_message_port_ids) { 146 if (!dispatcher_host_) 147 return; // Could be NULL in some tests. 148 149 std::vector<int> new_routing_ids; 150 dispatcher_host_->message_port_message_filter()-> 151 UpdateMessagePortsWithNewRoutes(sent_message_port_ids, 152 &new_routing_ids); 153 154 dispatcher_host_->Send( 155 new ServiceWorkerMsg_MessageToDocument( 156 kDocumentMainThreadId, provider_id(), 157 message, 158 sent_message_port_ids, 159 new_routing_ids)); 160 } 161 162 ServiceWorkerObjectInfo ServiceWorkerProviderHost::CreateHandleAndPass( 163 ServiceWorkerVersion* version) { 164 DCHECK(ValidateVersionForAssociation(version)); 165 ServiceWorkerObjectInfo info; 166 if (context_ && version) { 167 scoped_ptr<ServiceWorkerHandle> handle = 168 ServiceWorkerHandle::Create(context_, dispatcher_host_, 169 kDocumentMainThreadId, version); 170 info = handle->GetObjectInfo(); 171 dispatcher_host_->RegisterServiceWorkerHandle(handle.Pass()); 172 } 173 return info; 174 } 175 176 bool ServiceWorkerProviderHost::IsContextAlive() { 177 return context_ != NULL; 178 } 179 180 } // namespace content 181